通过方法/构造函数参数与隐式使用隐含

时间:2016-10-13 13:19:13

标签: scala

此代码编译并完全符合预期

class MyList[T](list: T)(implicit o: Ordering[T])

然而,这不是:

class MyList2[T](list: T) {
  val o = implicitly[Ordering[T]]
}

我不明白为什么。在构造类的第一个示例中,编译器将发现Ordering隐式,因为它将知道具体类型T。但在第二种情况下,它也应该找到隐含的,因为T已经是一个具体的类型。

4 个答案:

答案 0 :(得分:3)

  

在构造编译器类的第一个例子中   会发现Ordering隐式,因为它会知道具体的类型   吨。

在第一个示例中,需要在范围内具有隐式Ordering[T],以便编译器找到它。编译器本身不会“弥补”暗示。由于您已经通过第二个参数列表直接需要一个,如果存在这样的隐式,它将被传递给类构造函数。

  

但在第二种情况下,它也应该找到隐含的T   已经是一个具体的类型。

编译时T是具体类型这一事实无助于编译器找到隐含的内容。当我们说T是具体类型时,您必须记住,在调用站点,T只是一个泛型类型参数,仅此而已。如果您不帮助编译器,则无法保证具有隐式范围。您需要让方法提供隐式,这可以通过Context Bound

来完成
class MyList2[T: Ordering](list: T)

这要求在编译时存在类型T的排序。从语义上讲,这相当于您的第二个参数列表。

答案 1 :(得分:1)

您必须始终告诉编译器应为您的类型提供隐式。也就是说,您必须始终放置implicit o: Ordering[T]implicitly的作用是,它允许您在未命名的情况下访问隐式。请注意,您可以对隐式参数使用语法sugar(称为“上下文绑定”),在这种情况下implicitly成为必要:

class MyList2[T : Ordering](list: T) {
  val o = implicitly[Ordering[T]]
}

类型[T : Ordering]是“某些类型T的简写,”范围内存在隐式Ordering[T]“。这和写作一样:

class MyList2[T](list: T)(implicit o: Ordering[T]) {

}

但在这种情况下不需要implicitly,因为您可以通过其标识符o访问隐式参数。

答案 2 :(得分:0)

  

但在第二种情况下,它也应该找到隐含的,因为T已经是一个具体的类型。

Scala(和Java)泛型不像C ++模板那样工作。编译器不会在其他地方看到MyList2[Int],生成

class MyList2_Int(list: Int) {
  val o = implicitly[Ordering[Int]]
}

和typecheck 那个定义。它是MyList2本身,它没有具体的T

答案 3 :(得分:-1)

要使第二个工作,您需要使用context boundOrdering类型指定T

class MyList2[T : Ordering](list: T) {
  val o = implicitly[Ordering[T]]
}