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

时间:2010-06-05 22:01:46

标签: scala scala-2.8 context-bound

Scala 2.8的一个新功能是上下文边界。什么是上下文绑定以及它在哪里有用?

当然我先搜索(并找到例如this),但我找不到任何非常清晰和详细的信息。

4 个答案:

答案 0 :(得分:138)

Robert的回答涵盖了Context Bounds的技术细节。我会告诉你我们对它们意义的解释。

在Scala中,视图边界(A <% B)捕获了“可以被视为”的概念(而上限<:捕获了“是一个”的概念)。上下文绑定(A : C)表示“有一个”类型。您可以阅读有关清单的示例,因为“T有一个Manifest”。您链接到OrderedOrdering的示例说明了不同之处。方法

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

表示该参数可以看作是Ordered。与

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

表示该参数具有关联的Ordering

就使用而言,建立约定需要一段时间,但上下文边界优先于视图边界(view bounds are now deprecated)。一个建议是,当您需要将隐式定义从一个范围转移到另一个范围而不需要直接引用它时,首选上下文绑定(对于用于创建数组的ClassManifest来说肯定是这种情况)。 / p>

另一种思考视图边界和上下文边界的方法是,第一种方式是从调用者的范围转移隐式转换。第二个从调用者的范围传输隐式对象。

答案 1 :(得分:99)

您找到this article了吗?它涵盖了在数组改进的上下文中的新上下文绑定功能。

通常,带有上下文绑定的类型参数的格式为[T: Bound];它与类型为T的隐式参数一起扩展为普通类型参数Bound[T]

考虑从应用结果形成数组的方法tabulate 从0到给定长度的一系列数字上的给定函数f。最多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]的正确表示所必需的。需要通过将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
}

答案 2 :(得分:38)

(这是一个括号内容。首先阅读并理解其他答案。)

Context Bounds实际上概括了View Bounds。

所以,鉴于此代码用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

这也可以用Context Bound表示,借助于表示类型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

上下文绑定必须与类型为* => *的类型构造函数一起使用。但是类型构造函数Function1属于(*, *) => *种类。类型别名的使用部分地应用具有类型String的第二类型参数,从而产生正确类型的类型构造函数以用作上下文绑定。

有一项建议允许您在Scala中直接表达部分应用的类型,而不在特征中使用类型别名。然后你可以写:

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

答案 3 :(得分:16)

这是另一个括号内容。

作为Ben pointed out,上下文绑定表示类型参数和类型类之间的“has-a”约束。换句话说,它表示存在特定类型类的隐式值的约束。

当使用上下文绑定时,通常需要表示隐式值。例如,给定约束T : Ordering,通常需要满足约束的Ordering[T]实例。 As demonstrated here,可以使用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) }