简体   繁体   English

什么是Scala中的“上下文绑定”?

[英]What is a “context bound” in Scala?

One of the new features of Scala 2.8 are context bounds. Scala 2.8的一个新功能是上下文边界。 What is a context bound and where is it useful? 什么是上下文绑定以及它在哪里有用?

Of course I searched first (and found for example this ) but I couldn't find any really clear and detailed information. 当然我先搜索(例如找到这个 ),但我找不到任何非常清晰和详细的信息。

Robert's answer covers the techinal details of Context Bounds. Robert的答案涵盖了Context Bounds的技术细节。 I'll give you my interpretation of their meaning. 我会告诉你我们对它们意义的解释。

In Scala a View Bound ( A <% B ) captures the concept of 'can be seen as' (whereas an upper bound <: captures the concept of 'is a'). 在Scala中,视图边界( A <% B )捕获“可以被视为”的概念(而上限<:捕获'是'的概念)。 A context bound ( A : C ) says 'has a' about a type. 上下文绑定( A : C )表示“有一个”类型。 You can read the examples about manifests as " T has a Manifest ". 您可以阅读有关清单的示例“ T has a Manifest ”。 The example you linked to about Ordered vs Ordering illustrates the difference. 您链接到Ordered vs Ordering示例说明了差异。 A method 一个方法

def example[T <% Ordered[T]](param: T)

says that the parameter can be seen as an Ordered . 说参数可以看作是Ordered Compare with 与之比较

def example[T : Ordering](param: T)

which says that the parameter has an associated Ordering . 表示该参数具有关联的Ordering

In terms of use, it took a while for conventions to be established, but context bounds are preferred over view bounds ( view bounds are now deprecated ). 在使用方面,建立约定需要一段时间,但上下文边界优先于视图边界( 现在不推荐使用视图边界 )。 One suggestion is that a context bound is preferred when you need to transfer an implicit definition from one scope to another without needing to refer to it directly (this is certainly the case for the ClassManifest used to create an array). 一个建议是,当您需要将隐式定义从一个范围转移到另一个范围而不需要直接引用它时,首选上下文绑定(这对于用于创建数组的ClassManifest来说肯定是这种情况)。

Another way of thinking about view bounds and context bounds is that the first transfers implicit conversions from the caller's scope. 另一种思考视图边界和上下文边界的方法是,第一种方式是从调用者的范围转移隐式转换。 The second transfers implicit objects from the caller's scope. 第二个从调用者的范围传输隐式对象。

Did you find this article ? 你找到这篇文章了吗? It covers the new context bound feature, within the context of array improvements. 它涵盖了在数组改进的上下文中的新上下文绑定功能。

Generally, a type parameter with a context bound is of the form [T: Bound] ; 通常,具有上下文边界的类型参数的形式为[T: Bound] ; it is expanded to plain type parameter T together with an implicit parameter of type Bound[T] . 它与一个类型为Bound[T]的隐式参数一起扩展为普通类型参数T

Consider the method tabulate which forms an array from the results of applying a given function f on a range of numbers from 0 until a given length. 考虑方法tabulate ,该表格从在从0到给定长度的数字范围内应用给定函数f的结果形成数组。 Up to Scala 2.7, tabulate could be written as follows: 对于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
}

In Scala 2.8 this is no longer possible, because runtime information is necessary to create the right representation of Array[T] . 在Scala 2.8中,这不再可能,因为运行时信息是创建Array[T]的正确表示所必需的。 One needs to provide this information by passing a ClassManifest[T] into the method as an implicit parameter: 需要通过将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
}

As a shorthand form, a context bound can be used on the type parameter T instead, giving: 作为简写形式,可以在类型参数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
}

(This is a parenthetical note. Read and understand the other answers first.) (这是一个括号内容。请先阅读并理解其他答案。)

Context Bounds actually generalize View Bounds. Context Bounds实际上概括了View Bounds。

So, given this code expressed with a View Bound: 所以,鉴于这个代码用View Bound表示:

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

This could also be expressed with a Context Bound, with the help of a type alias representing functions from type F to type T . 这也可以用Context Bound表示,借助于表示从FT类的函数的类型别名。

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

A context bound must be used with a type constructor of kind * => * . 上下文绑定必须与类型* => *的类型构造函数一起使用。 However the type constructor Function1 is of kind (*, *) => * . 但是类型构造Function1是种类(*, *) => * The use of the type alias partially applies second type parameter with the type String , yielding a type constructor of the correct kind for use as a context bound. 类型别名的使用部分地应用具有String类型的第二类型参数,从而产生正确类型的类型构造函数以用作上下文绑定。

There is a proposal to allow you to directly express partially applied types in Scala, without the use of the type alias inside a trait. 有一个建议允许您直接在Scala中表达部分应用的类型,而不使用特征中的类型别名。 You could then write: 然后你可以写:

def f3[T : [X](X => String)](t: T) = 0 

This is another parenthetical note. 这是另一个括号内容。

As Ben pointed out , a context bound represents a "has-a" constraint between a type parameter and a type class. 正如Ben所指出的 ,上下文绑定表示类型参数和类型类之间的“has-a”约束。 Put another way, it represents a constraint that an implicit value of a particular type class exists. 换句话说,它表示存在特定类型类的隐式值的约束。

When utilizing a context bound, one often needs to surface that implicit value. 在利用上下文绑定时,通常需要表达隐式值。 For example, given the constraint T : Ordering , one will often need the instance of Ordering[T] that satisfies the constraint. 例如,给定约束T : Ordering ,通常需要满足约束的Ordering[T]实例。 As demonstrated here , it's possible to access the implicit value by using the implicitly method or a slightly more helpful context method: 如此处所示 ,可以通过使用implicitly方法或稍微有用的context方法来访问隐式值:

def **[T : Numeric](xs: Iterable[T], ys: Iterable[T]) = 
   xs zip ys map { t => implicitly[Numeric[T]].times(t._1, t._2) }

or 要么

def **[T : Numeric](xs: Iterable[T], ys: Iterable[T]) =
   xs zip ys map { t => context[T]().times(t._1, t._2) }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM