Расширение класса со многими реализациями, каждый из которых имеет основные методы в Scala - PullRequest
2 голосов
/ 16 сентября 2011

представьте, что у меня есть класс Tokenizer с одним абстрактным методом.

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

Я реализую ряд токенизаторов, которые предоставляют реализацию.Я бы хотел, чтобы у каждого из этих токенизаторов был основной метод.Моей первой мыслью было написать код, подобный следующему:

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.Есть ли лучший способ сделать это?

ОБНОВЛЕНИЕ: эта проблема, кажется, вызвана неявным параметром конструктора model TokenizerOne.

1 Ответ

7 голосов
/ 17 сентября 2011

Вот сокращенный пример кода, который выдает ту же ошибку,

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")).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...