Проблема здесь не в том, что toString
перегружен на Foo
, так как один из других (теперь удаленных) ответов утверждает (вы можете попробовать перегрузить asString
аналогично, и это будет работать), это то, чтоtoString
, который вы импортируете, сталкивается с toString
включающего класса (в вашем случае это некий синтетический объект, составленный из REPL).
Я думаю, что следующие неявные примеры (которые также неНе используйте «встроенные» имена методов, такие как toString
), чтобы показать проблему немного яснее:
class Foo {
def asString(i: Int): String = "this is the one from Foo!"
}
class Bar {
def asString(i: Int): String = "this is the one from Bar!"
}
object Demo extends Bar {
val instance = new Foo
import instance._
println(asString(23))
}
Это будет использовать asString
из Bar
, даже если вы думаете, чтоимпортированный будет иметь приоритет:
scala> Demo
this is the one from Bar!
res1: Demo.type = Demo$@6987a133
На самом деле он будет использовать определение из Bar
, даже если аргументы не совпадают:
class Foo {
def asString(i: Int): String = "this is the one from Foo!"
}
class Bar {
def asString(): String = "this is the one from Bar!"
}
object Demo extends Bar {
val instance = new Foo
import instance._
println(asString(23))
}
Это не компилируется:
<pastie>:25: error: no arguments allowed for nullary method asString: ()String
println(asString(324))
^
Теперь мы можем сделать это больше похожим на ваш исходный код:
class Foo {
implicit def asString(i: Int): String = "this is the one from Foo!"
def foo(s: String): String = s
}
class Bar {
def asString(): String = "this is the one from Bar!"
}
object Demo extends Bar {
val instance = new Foo
import instance._
println(foo(23))
}
Это происходит с той же ошибкой, что и вы, по той же причине: импортированное неявное преобразованиескрыт по определению с тем же именем в включающем классе.
Сноска 1
Вы спросили следующее:
Почему имя implicit def
имеет значение?
Именавлияет на материю все время .Так работает язык.Например:
scala> List(1, 2, 3) + ""
res0: String = List(1, 2, 3)
scala> trait Garbage
defined trait Garbage
scala> implicit val any2stringadd: Garbage = new Garbage {}
any2stringadd: Garbage = $anon$1@5b000fe6
scala> List(1, 2, 3) + ""
<console>:13: error: value + is not a member of List[Int]
List(1, 2, 3) + ""
^
Мы определили неявное значение, которое скрывает неявное преобразование any2stringadd
в scala.Predef
.(Да, это ужасно.)
Сноска 2
Я думаю, что здесь, вероятно, есть ошибка компилятора, по крайней мере, что касается сообщения об ошибке.Если вы немного измените положение в моей второй версии выше, например:
class Foo {
def asString(i: Int): String = "this is the one from Foo!"
}
class Bar {
def asString(): String = "this is the one from Bar!"
}
object Demo extends Bar {
def test(): Unit = {
val instance = new Foo
import instance._
println(asString(23))
}
}
… вы получите гораздо более разумное сообщение:
<pastie>:26: error: reference to asString is ambiguous;
it is both defined in class Bar and imported subsequently by
import instance._
println(asString(23))
^
На мой взгляд, этопочти наверняка то, что компилятор должен рассказать вам в вашем первоначальном случае.Я также не уверен, почему скрытое неявное значение рассматривается для преобразования вообще, но это, как вы можете сказать, если вы запускаете свой код в REPL с -Xlog-implicits
:
scala> foo(23)
<console>:16: toString is not a valid implicit value for Int(23) => String because:
no arguments allowed for nullary method toString: ()String
foo(23)
^
Так чтоПохоже, неявность стирается на другом toString
?Если честно, я понятия не имею, что здесь происходит, но я на 90% уверен, что это ошибка.