什么是“上下文绑定”?在斯卡拉?

发布于 2024-09-04 08:20:38 字数 224 浏览 4 评论 0原文

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

当然,我首先搜索(并发现例如 this),但我找不到任何真正清晰详细的信息。

One of the new features of Scala 2.8 are context bounds. 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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

不知所踪 2024-09-11 08:20:38

罗伯特的回答涵盖了上下文边界的技术细节。我将向您解释它们的含义。

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

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

表示该参数可以被视为Ordered。与

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

它进行比较,表明该参数具有关联的Ordering

在使用方面,建立约定需要一段时间,但上下文边界优于视图边界(视图边界现已弃用)。一个建议是,当您需要将隐式定义从一个作用域传输到另一个作用域而不需要直接引用它时,首选上下文绑定(对于用于创建数组的 ClassManifest 来说肯定是这种情况) )。

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

Robert's answer covers the techinal details of 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'). A context bound (A : C) says 'has a' about a type. You can read the examples about manifests as "T has a Manifest". The example you linked to about Ordered vs Ordering illustrates the difference. A method

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

says that the parameter can be seen as an Ordered. Compare with

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

which says that the parameter has an associated 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).

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.

忆依然 2024-09-11 08:20:38

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

一般来说,具有上下文绑定的类型参数的形式为[T: Bound];它被扩展为普通类型参数 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] 的正确表示。需要通过将 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
}

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]; it is expanded to plain type parameter T together with an implicit parameter of type Bound[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. Up to Scala 2.7, tabulate could be
written as follows:

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]. One needs to provide this information by passing a ClassManifest[T] into the method as an implicit parameter:

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:

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
}
百变从容 2024-09-11 08:20:38

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

上下文边界实际上概括了视图边界。

因此,给定用 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 

(This is a parenthetical note. Read and understand the other answers first.)

Context Bounds actually generalize View Bounds.

So, given this code expressed with a 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.

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 (*, *) => *. 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.

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. You could then write:

def f3[T : [X](X => String)](t: T) = 0 
樱娆 2024-09-11 08:20:38

这是另一个括号注释。

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

当使用上下文绑定时,人们通常需要显示该隐式值。例如,给定约束 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) }

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. 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. As demonstrated here, it's possible to access the implicit value by using the implicitly method or a slightly more helpful context method:

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) }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文