2013-03-21 29 views
1

如果有現有的Java類pkg.Test,爲什麼需要類型同義詞來定義在Scala中匹配Java類的patten抽取器?

package pkg; 
public class Test { 
    public int v; 
    public Test(int v) { this.v = v; } 
} 

試圖通過定義斯卡拉同伴對象

package pkg 
object Test{ 
    def unapply(t : Test) : Option[Int] = Some(t.v) 
} 

產生的錯誤,使提取器「測試已經被定義爲對象測試」。 然而,一切似乎如果我做了Java類的同義詞在一個新的包

package pkg 
package object matchers { 
    type Test = pkg.Test 
} 

工作,在新的包

package pkg.matchers 
object Test { 
    def unapply(t : Test) : Option[Int] = Some(t.v) 
} 

現在定義相應的對象的模式,所有成員都的原始類可從新包中提取

import pkg.matchers._ 
object main { 
    def main(args : Array[String]) { 
    val t = new Test(1) 
    t match {case Test(v) => println(v)} 
    println(t.v) 
    } 
} 

添加類型同義詞讓這項工作看起來很奇怪。除了必須使用新的軟件包之外,這種方式添加模式匹配還有什麼問題嗎?有什麼方法可以使原始包裝中的提取器可用?

回答

4

這是因爲當與Java庫交互時,Scala需要一種將Java的靜態方法映射到Scala的單例對象的方法。

例如,如果您有以下Java類:

package pkg; 

class Test { 
    public static void printHello() { 
    System.out.println("Hello"); 
    } 
} 

,我們怎樣才能斯卡拉調用printHello?它將如下所示:

import pkg.Test 
Test.printHello() 

正如你所看到的,語法是在object Test調用的方法完全相同。從這一點來看,已經定義了Test單身人士,並且您不能用相同的FQN兩次定義object

這就是爲什麼你需要定義pkg.matchers.Test所以它不會與pkg.Test衝突。

和Scala的編譯器足夠聰明弄清楚,pkg.matchers.Test是使用new關鍵字可能無法構造它一個單身,所以,當你寫new Test(1),它是pkg.Test,而不是pkg.matchers.Test。這就是爲什麼你可以在你的代碼示例中同時使用它們。

其實,你並不需要type Test = pkg.Test可言,下面是工作的罰款:

package pkg 

package matchers { 
    object Test { 
    def unapply(t : Test) : Option[Int] = Some(t.v) 
    } 
} 

object main { 

    import pkg.matchers._ 

    def main(args : Array[String]) { 

    val t = new Test(1) 
    t match {case Test(v) => println(v)} 
    println(t.v) 
    } 
} 

更新

提取不需要爲伴侶對象,這意味着你不t需要相應的類。任何objectunapply方法可以作爲提取器。

object StringLength { 
    def unapply(x: String): Option[Int] = Some(x.length) 
} 

object Main { 

    def main(args: Array[String]) { 

    "Hello World" match { 
     case StringLength(x) => println("length:" + x) 
    } 
    } 
} 

因此,如果主要方法是不是在pkg,您有以下選擇:

  1. 重命名提取到另一個名字,因此編譯器可以知道你正在使用提取。

  2. 使用FQN,因此編譯器知道您訪問pkg.matchers.Test而不是pkg.Test

    package pkg.matchers { 
    
        import pkg._ 
    
        object Test { 
        def unapply(t : Test) : Option[Int] = Some(t.v) 
        } 
    } 
    
    object Main { 
    
        def main(args: Array[String]) { 
    
        import pkg.Test 
    
        val t = new Test(1) 
        t match {case pkg.matchers.Test(v) => println(v)} 
        println(t.v) 
    
        } 
    
    } 
    
  3. 重命名pkg.Test另一名與import語法,所以它不會與pkg.matchers.Test衝突。

    object Main { 
    
        def main(args: Array[String]) { 
    
        import pkg.{Test => JTest} 
        import pkg.matchers.Test 
    
        val t = new JTest(1) 
        t match {case Test(v) => println(v)} 
        println(t.v) 
    
        } 
    } 
    
  4. 剛剛從pkg進口的一切,擁有自營pkg.matcher.Test明確。

    def main(args: Array[String]) { 
    
        import pkg._ 
        import pkg.matchers.Test 
    
        val t = new Test(1) 
        t match {case Test(v) => println(v)} 
        println(t.v) 
    
        } 
    
+0

這將如何工作,如果主是不是在或正在PKG?我發現它與pkg的靜態部分沒有衝突。測試很重要,並且提取器實際上不是一個伴隨對象,但是範圍很混亂。將pkg.Test顯式導入到main的開始會產生一個錯誤,即該模式中的「Test」模糊不清,因爲它被導入了兩次,而以某種方式從相同的包中獲取它只是一次。 – Brandon 2013-03-21 06:10:40

+0

只有你的第四個選擇做我想要的 - 讓模式和原始類都可以不合格地訪問。在規範中我沒有看到任何解釋爲什麼導入pkg._應該與顯式導入所有名稱不同,但將行更改爲導入pkg.Test會生成與以前相同的變量。不過,這可能是另一個問題。感謝您的幫助。 – Brandon 2013-03-21 19:31:26

相關問題