Scala 2.8的新功能之一是上下文边界。什么是上下文绑定,它在哪里有用?
当然,我首先进行了搜索(并找到了this),但是找不到任何真正清晰详细的信息。
Scala 2.8的新功能之一是上下文边界。什么是上下文绑定,它在哪里有用?
当然,我首先进行了搜索(并找到了this),但是找不到任何真正清晰详细的信息。
Answers:
您找到这篇文章了吗?在数组改进的上下文中,它涵盖了新的上下文绑定功能。
通常,带有上下文绑定的类型参数的形式为[T: Bound]
; 它与type T
的隐式参数一起扩展为普通类型参数Bound[T]
。
考虑tabulate
从将给定函数f应用于从0到给定长度的数字范围内的结果形成数组的方法。在Scala 2.7之前,表格可以编写如下:
def tabulate[T](len: Int, f: Int => T) = {
val xs = new Array[T](len)
for (i <- 0 until len) xs(i) = f(i)
xs
}
在Scala 2.8中,这不再可能,因为运行时信息对于创建的正确表示是必要的Array[T]
。需要通过将a 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
}
作为一种简写形式,可以在type参数上使用上下文绑定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
}
Robert的答案涵盖了Context Bounds的技术细节。我将解释它们的含义。
在Scala中,“视图绑定”(A <% B
)捕获了“可以被视为” <:
的概念(而上限捕获了“是a”的概念)。上下文绑定(A : C
)对类型说“有”。您可以阅读有关清单的示例,因为清单中的“ T
具有Manifest
”。您链接到about Ordered
与的Ordering
示例说明了差异。一个方法
def example[T <% Ordered[T]](param: T)
表示该参数可以视为Ordered
。与之比较
def example[T : Ordering](param: T)
表示该参数具有关联的Ordering
。
在使用方面,建立约定花费了一段时间,但是上下文边界比视图边界更受青睐(视图边界现在已弃用)。一个建议是,当您需要将隐式定义从一个范围转移到另一个范围而不需要直接引用它时(最好是ClassManifest
用于创建数组的情况),最好使用上下文绑定 。
考虑视图范围和上下文范围的另一种方法是,第一种方法从调用者的作用域转移隐式转换。第二种方法从调用者的作用域传输隐式对象。
has a
对我来说更有意义]
(这是带括号的注释。请先阅读并理解其他答案。)
上下文边界实际上是概括视图边界。
因此,鉴于此代码使用“查看范围”表示:
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
这也可以通过上下文绑定(Context Bound)来表示,它借助于表示类型从type F
到type的函数的类型别名来实现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
是一种(*, *) => *
。使用类型别名会部分地将第二个类型参数与type配合使用String
,从而产生正确类型的类型构造函数,以用作上下文绑定。
有一种建议可以让您直接在Scala中表达部分应用的类型,而无需在特征内使用类型别名。然后,您可以编写:
def f3[T : [X](X => String)](t: T) = 0
From
的类型To[String]
。我们没有为提供类型参数From
,因此我们引用的是类型构造函数,而不是类型。这种类型的构造函数是正确的,可以用作上下文绑定- * -> *
。T
通过要求type 的隐式参数来限制type参数To[String]#From[T]
。展开类型别名,瞧,剩下的就是Function1[String, T]
。
这是另一个括号。
正如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) }