扩展一个具有许多实现的类,每个实现都包含Scala中的主要方法

sch*_*mmd 2 scala

想象一下,我有一个带有单个抽象方法的Tokenizer类.

trait Tokenizer {
    def tokenize(sentence: String): List[String]
}
Run Code Online (Sandbox Code Playgroud)

我将实现一些提供实现的tokenizer.我希望每个Tokenizer都有一个main方法.我的第一个想法是编写这样的代码:

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) {
}
Run Code Online (Sandbox Code Playgroud)

但是,我得到错误"超级构造函数不能传递自引用,除非参数是通过名称声明的".我可以重命名object TokenizerOne,object TokenizerOneMain但我想保持它与class.有一个更好的方法吗?

更新:此问题似乎是由modelTokenizerOne 的隐式构造函数参数引起的.

Kip*_*ros 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
Run Code Online (Sandbox Code Playgroud)

字节码有助于解释发生了什么.来自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);
...
Run Code Online (Sandbox Code Playgroud)

我们看到该类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
Run Code Online (Sandbox Code Playgroud)

啊,这是在伴侣对象中定义的,它属于类Bar$(只有Scala编译器应该知道它).

所以似乎正在发生的事情是,extends Foo(new Bar())Bar在初始化Bar超类(在Bar实际构造对象之前)尝试访问对象中的方法.

如果这不是Scala编译器中的错误,那么这是一个令人困惑的错误消息!我不能说哪个.我在错误跟踪器中提交了问题SI-5000.

作为解决方法,您可以避免使用默认值:object Bar extends Foo(new Bar("bar")).