此代码编译并完全符合预期
class MyList[T](list: T)(implicit o: Ordering[T])
然而,这不是:
class MyList2[T](list: T) {
val o = implicitly[Ordering[T]]
}
我不明白为什么。在构造类的第一个示例中,编译器将发现Ordering隐式,因为它将知道具体类型T
。但在第二种情况下,它也应该找到隐含的,因为T
已经是一个具体的类型。
答案 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 bound为Ordering
类型指定T
:
class MyList2[T : Ordering](list: T) {
val o = implicitly[Ordering[T]]
}