Scala 2.8的一个新特性是上下文界定(context bounds)。什么是上下文界定以及它有哪些用处?
当然,我先进行了搜索(例如在这里找到了一些信息),但是我没有找到任何真正清晰和详细的信息。
Scala 2.8的一个新特性是上下文界定(context bounds)。什么是上下文界定以及它有哪些用处?
当然,我先进行了搜索(例如在这里找到了一些信息),但是我没有找到任何真正清晰和详细的信息。
罗伯特的答案涵盖了上下文界限的技术细节。我会给出我的解释。
在Scala中,视图界限(A <% B
)捕获“可以被视为”的概念(而上限 <:
捕获“是一个”的概念)。上下文界限(A:C
)表示一个类型“拥有”某个特性。您可以将关于标记的示例阅读为“T
拥有一个Manifest
”。您链接到的关于Ordered
与Ordering
的示例说明了区别。一个方法
def example[T <% Ordered[T]](param: T)
说这个参数可以被看作是一个Ordered
。与之比较
def example[T : Ordering](param: T)
该参数具有相关的 Ordering
。
在使用方面,花费了一些时间才确立了惯例,但是语境限定符比视图限定符更受欢迎 (现在已弃用视图限定符)。一个建议是:当您需要在不直接引用它的情况下从一个作用域传递一个隐式定义时(这对于用于创建数组的ClassManifest
绝对是这种情况),建议使用语境限定符。
另一种理解视图限定符和语境限定符的方式是:前者从调用方的范围传递隐式转换。后者从调用方的范围传递隐式对象。
has a
对我来说更有意义] - Shankar您是否看到了这篇文章?它涵盖了新的上下文界限特性,以数组改进为背景。
通常,带有上下文界限的类型参数形式为[T: Bound]
;它被扩展为普通类型参数T
和类型为Bound[T]
的隐式参数。
考虑方法tabulate
,它通过在从0到给定长度的数字范围上应用给定函数f的结果来形成一个数组。在Scala 2.7之前,可以将tabulate写成以下形式:
def tabulate[T](len: Int, f: Int => T) = {
val xs = new Array[T](len)
for (i <- 0 until len) xs(i) = f(i)
xs
}
Array[T]
表示。必须通过将ClassManifest[T]
作为隐式参数传递给方法来提供此信息:def tabulate[T](len: Int, f: Int => T)(implicit m: ClassManifest[T]) = {
val xs = new Array[T](len)
for (i <- 0 until len) xs(i) = f(i)
xs
}
T
上使用上下文绑定,即:def tabulate[T: ClassManifest](len: Int, f: Int => T) = {
val xs = new Array[T](len)
for (i <- 0 until len) xs(i) = f(i)
xs
}
(这是一个括号注释。先阅读和理解其他答案。)
上下文界限实际上是一般化的视图界限。
因此,考虑到以下使用视图界限表达的代码:
scala> implicit def int2str(i: Int): String = i.toString
int2str: (i: Int)String
scala> def f1[T <% String](t: T) = 0
f1: [T](t: T)(implicit evidence$1: (T) => String)Int
这也可以通过上下文边界来表达,借助于一个类型别名,表示从类型F
到类型T
的函数。
scala> trait To[T] { type From[F] = F => T }
defined trait To
scala> def f2[T : To[String]#From](t: T) = 0
f2: [T](t: T)(implicit evidence$1: (T) => java.lang.String)Int
scala> f2(1)
res1: Int = 0
一个上下文边界必须与 kind 为 * => *
的类型构造器一起使用。然而,类型构造器 Function1
的 kind 是 (*, *) => *
。使用类型别名部分应用第二个类型参数,其类型为 String
,产生了一个正确种类的类型构造器,可用作上下文边界。
有一个提案允许您在 Scala 中直接表达部分应用的类型,而无需在特质中使用类型别名。然后您可以编写:
def f3[T : [X](X => String)](t: T) = 0
To[String]
的类型成员 From
。我们没有为 From
提供类型参数,因此我们引用的是类型构造函数,而不是类型本身。这个类型构造函数是正确的种类,可以用作上下文边界——* -> *
。这通过要求一个类型为 To[String]#From[T]
的隐式参数来限制类型参数 T
。扩展类型别名,你就得到了 Function1[String, T]
。 - retronym这是另一个括号注释。
正如Ben所指出的,上下文界定表示类型参数和类型类之间的“具有”约束。换句话说,它表示特定类型类的隐式值存在的约束。
在使用上下文界定时,通常需要表明该隐式值。例如,给定约束T : Ordering
,通常需要满足约束的Ordering[T]
实例。正如此处所示,可以通过使用implicitly
方法或稍微更有帮助的context
方法来访问隐式值:
def **[T : Numeric](xs: Iterable[T], ys: Iterable[T]) =
xs zip ys map { t => implicitly[Numeric[T]].times(t._1, t._2) }
def **[T : Numeric](xs: Iterable[T], ys: Iterable[T]) =
xs zip ys map { t => context[T]().times(t._1, t._2) }