我可以在Predef的 API 文档中看到它们是通用函数类型 (From) => To 的子类,但仅此而已。嗯什么?也许某处有文档,但是搜索引擎不能很好地处理像“<:<”这样的“名称”,所以我一直无法找到它。
后续问题:我什么时候应该使用这些时髦的符号/类,为什么?
这些称为 广义类型约束 。它们允许您从类型参数化的类或特征中 进一步约束 其类型参数之一。这是一个例子:
case class Foo[A](a:A) { // 'A' can be substituted with any type // getStringLength can only be used if this is a Foo[String] def getStringLength(implicit evidence: A =:= String) = a.length }
隐式参数evidence由编译器提供,当且仅A当String. 你可以把它看作是一个证明 —— 论证本身并不重要,只知道它存在。 [编辑:嗯,从技术上讲,它实际上很重要,因为它表示从 to的隐式转换 ,这使您可以调用 而不会让编译器对您大喊大叫]A``String A``String``a.length
evidence
A
String
A``String
A``String``a.length
现在我可以像这样使用它:
scala> Foo("blah").getStringLength res6: Int = 4
但是,如果我尝试将它与Foo包含 a 以外的其他内容一起使用String:
Foo
scala> Foo(123).getStringLength <console>:9: error: could not find implicit value for parameter evidence: =:=[Int,String]
您可以将该错误理解为“无法找到 Int == String 的证据”......应该是这样!对类型的限制超出getStringLength一般 要求 ;即,您只能在 a上调用。这个约束是在编译时强制执行的,这很酷!A``Foo``getStringLength``Foo[String]
getStringLength
A``Foo``getStringLength``Foo[String]
<:<和<%<工作类似,但略有不同:
<:<
<%<
A =:= B
A <:< B
<:
A <%< B
<%
@retronym 的这个片段很好地解释了这种事情过去是如何完成的,以及通用类型约束现在如何使它变得更容易。
附录
为了回答您的后续问题,诚然,我给出的示例非常做作,显然没有用。但是想象一下,用它来定义一个List.sumInts方法之类的东西,它加起来一个整数列表。您不想允许在任何 old 上调用此方法List,只是在List[Int]. 但是List类型构造函数不能这么受限制;您仍然希望能够拥有字符串、foos、bars 和诸如此类的列表。因此,通过在 上放置通用类型约束sumInts,您可以确保 该方法 具有只能在 上使用的附加约束List[Int]。本质上,您正在为某些类型的列表编写特殊情况代码。
List.sumInts
List
List[Int]
sumInts