gpt4 book ai didi

如果 def 名称是 toString,Scala 隐式 def 不起作用

转载 作者:行者123 更新时间:2023-12-04 22:02:48 30 4
gpt4 key购买 nike

此代码无法编译:

object Foo {
implicit def toString(i: Int): String = i.toString
def foo(x: String) = println(x)
foo(23)
}

上面的代码无法编译,并出现以下错误:
error: type mismatch;
found : scala.this.Int(23)
required: String
foo(23)

但是,这段代码会编译
object Foo {
implicit def asString(i: Int): String = i.toString
def foo(x: String) = println(x)
foo(23)
}

为什么 implicit def的名称应该很重要?

笔记:
如果该方法被命名为 equals,它也不会工作,但它的作品,如果它被命名为 hashCodeclone等。

最佳答案

这里的问题不在于 toStringFoo 上重载,正如其他(现已删除)答案之一所争论的(您可以尝试类似地重载 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

你问了以下问题:

Why does the name of an implicit def should matter?



隐含的名称一直很重要。这就是语言的工作方式。例如:
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))
^

在我看来,这几乎肯定是编译器应该在您的原始案例中告诉您的那种事情。我也不确定为什么在转换时会考虑隐藏的隐式,但确实如此,因为您可以判断是否使用 -Xlog-implicits 在 REPL 中运行代码:
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% 肯定这是一个错误。

关于如果 def 名称是 toString,Scala 隐式 def 不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54872032/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com