2011-09-16 152 views
2

想象一下,我有一個帶有單個抽象方法的Tokenizer類。擴展一個類,每個類都有很多實現,每個實現都有Scala中的主要方法

trait Tokenizer { 
    def tokenize(sentence: String): List[String] 
} 

我將實現一些提供實現的標記器。我希望每個Tokenizer都有一個主要的方法。我首先想到的是寫這樣的代碼:

abstract class TokenizerMain(tokenizer: Tokenizer) { 
    def main(args: Array[String]) = println(tokenizer.tokenize(args(0)).mkString(" ")) 
} 

class TokenizerOne(val model: String = "foo") extends Tokenizer { 
    def tokenize(sentence: String) = List("asdf") 
} 

object TokenizerOne extends TokenizerMain(new TokenizerOne) { 
} 

但是,我得到的錯誤「超級構造函數不能被傳遞一個自我引用,除非參數是通過名稱聲明」。我可以將object TokenizerOne重命名爲object TokenizerOneMain,但我想保留它與class相同。有一個更好的方法嗎?

更新:此問題似乎是由TokenizerOne的隱式構造函數參數model造成的。

回答

7

這裏有一個減少代碼示例,給出了同樣的錯誤,

class Foo(t: Any) 
class Bar(x: String = "bar") 
object Bar extends Foo(new Bar()) 
    //     ^
    // Error, super constructor cannot be passed a self reference unless 
    // parameter is declared by-name 

字節碼可以解釋發生了什麼事情。從REPL,

scala> class Foo(t: Any) 

scala> class Bar(x: String = "bar") 

scala> :javap -v Bar 

Compiled from "<console>" 
public class Bar extends java.lang.Object implements scala.ScalaObject 
... 
{ 
public Bar(java.lang.String); 
... 

我們看到類Bar只有一個構造函數,它需要一個String參數。但我們知道Bar也有一個構造函數,它使用默認值x = "bar",這是從哪裏來的?

scala> :javap -v Bar$ 
... 
public java.lang.String init$default$1(); 
    Code: 
    Stack=1, Locals=1, Args_size=1 
    0: ldC#16; //String bar 
    2: areturn 
    LineNumberTable: 
    line 7: 0 

啊,在同伴的對象,屬於Bar$類(僅限Scala編譯器應該知道的事情)的已定義。

那麼,什麼似乎是發生的是,在extends Foo(new Bar())你想Bar的超一流的初始化過程中訪問對象Bar的方法(這是對象Bar之前實際上是構造)。

如果這不是Scala編譯器中的錯誤,那麼這是一個令人困惑的錯誤消息!我不能說哪個。我在錯誤跟蹤器中提交了問題SI-5000

作爲解決方法,您可以避免默認值:object Bar extends Foo(new Bar("bar"))

+0

我正在使用2.9.1。我忘記了TokenizerOne類的隱式構造函數參數 - 我的歉意。隨着這個構造函數參數的增加,問題就會發生。 – schmmd

相關問題