3

我正在阅读Scala in Depth,第 5 章关于隐式。作者在第 102 页这样说:

用于隐式视图的隐式范围与隐式参数相同。但是当编译器在寻找类型关联时,它使用它试图[我的重点]转换的类型,而不是它试图转换成的类型。

然而,几页之后,他展示了一个带有complexmath.ComplexNumber类的示例。你 import i,它是一个ComplexNumber,并调用它的*方法,它接受一个ComplexNumber参数。

import complexmath.i
i * 1.0

要将 1.0 转换为 a ComplexNumber,这会找到一个隐式转换,其定义如下:

package object complexmath {
  implicit def realToComplex(r: Double) = new ComplexNumber(r, 0)
  val i = ComplexNumber(0, 1)    

但这与第一个陈述相矛盾,不是吗?它需要找到Double => ComplexNumber. 为什么它在complexmath包中查找,这是隐含范围的一部分 forComplexNumber但不是 for Double

4

4 回答 4

2

该规范说关于视图:

隐式范围是 T => pt 之一。

即 ,Function[T, pt]因此隐式范围包括与T和相关的类pt,转换的源和目标。

scala> :pa
// Entering paste mode (ctrl-D to finish)

class B
class A
object A { implicit def x(a: A): B = new B }

// Exiting paste mode, now interpreting.

warning: there were 1 feature warning(s); re-run with -feature for details
defined class B
defined class A
defined object A

scala> val b: B = new A
b: B = B@63b41a65

scala> def f(b: B) = 3 ; def g = f(new A)
f: (b: B)Int
g: Int

scala> :pa
// Entering paste mode (ctrl-D to finish)

class A
class B
object B { implicit def x(a: A): B = new B }

// Exiting paste mode, now interpreting.

scala> val b: B = new A
b: B = B@6ba3b481
于 2014-03-13T07:10:03.910 回答
1

我认为你误解了他的文字。

编译器将在所有可用范围内查找隐式转换,直到找到合适的范围。

在您指定的示例中,它将找到由complexmath包提供的示例。

然而,我们在这里感兴趣的是“合适的人”的定义。在隐式转换的情况下,编译器将寻找* Double * 到预期类型ComplexNumber的转换。

换句话说,它将检查* Double * 的所有转换直到找到可以将Double转换为目标类型的转换。

作者 Josh 并不是说​​编译器需要在与Double对象关联的对象中定义转换。可以在任何地方定义转换。

在这种特殊情况下,转换是在与ComplexNumber对象关联的包对象中定义的。这很正常,是“希望”与Double兼容的 ComplexNumber 对象。

并且由于该用法暗示了ComplexNumber的导入以及包“ complexmath ”的导入,因此转换将始终在范围内。

于 2014-03-12T23:27:00.480 回答
1

所以这更多是关于编译器已经*知道*关于表达式的内容。

您在示例中:

import complexmath.i
i * 1.0

编译器从以下方面着手:

1)我有一个 for 的类型i,它是Complex 2)我有一个方法 on icalled *,它需要一个类型的参数Complex 3)你传递给我一个Int,但我需要一个Complex. 让我们看看我是否有隐含的意思。

此示例有效,因为该*方法是在 Complex 上定义的。

希望有帮助!

于 2014-03-12T23:58:50.693 回答
0

源或目标都有效:

object Foo {
  implicit def bar(b: Bar): Foo = new Foo {}
  implicit def foo(f: Foo): Bar = new Bar {}
}
trait Foo
trait Bar

implicitly[Foo => Bar]  // ok
implicitly[Bar => Foo]  // ok

val b = new Bar {}
val bf: Foo = b  // ok
val f = new Foo {}
val fb: Bar = f  // ok

所以我认为这句话是错误的(?)

于 2014-03-12T23:05:25.600 回答