以简单的方式,上下文和视图界限是什么?它们之间有什么区别?

一些易于遵循的示例也很棒!

有帮助吗?

解决方案

我认为这已经被问到了,但是,如果是这样,则在“相关”栏中并不明显。因此,这里是:

什么是绑定的视图?

一个 视图绑定 是在Scala中引入的一种机制,以实现某种类型的使用 A 仿佛 这是某种类型 B. 。典型的语法是:

def f[A <% B](a: A) = a.bMethod

换句话说, A 应该有隐性的转换为 B 可用,以便打电话 B 类型对象的方法 A. 。标准库中最常见的视图范围用法(无论如何在Scala 2.8.0之前)与 Ordered, , 像这样:

def f[A <% Ordered[A]](a: A, b: A) = if (a < b) a else b

因为一个人可以转换 A 进入 Ordered[A], ,因为 Ordered[A] 定义方法 <(other: A): Boolean, ,我可以使用表达式 a < b.

请注意 视图边界被弃用, ,您应该避开它们。

什么是上下文绑定?

上下文范围是在Scala 2.8.0中引入的,通常与所谓的 类型类模式, ,一种模拟Haskell类型类提供的功能的代码模式,尽管以更详细的方式。

虽然绑定的视图可以与简单类型一起使用(例如, A <% String),上下文界限需要一个 参数化类型, , 如 Ordered[A] 上面,但不像 String.

上下文界描述了隐式 价值, ,而不是查看Bound的隐式 转换. 。它用于声明某种类型 A, ,类型有隐式值 B[A] 可用的。语法是这样的:

def f[A : B](a: A) = g(a) // where g requires an implicit value of type B[A]

这比绑定的视图更令人困惑,因为它不清楚如何使用它。在Scala中使用的常见示例是:

def f[A : ClassManifest](n: Int) = new Array[A](n)

一个 Array 对参数化类型的初始化需要 ClassManifest 为了获得与类型擦除和阵列的非蠕虫性质有关的神秘原因。

库中的另一个非常常见的例子更为复杂:

def f[A : Ordering](a: A, b: A) = implicitly[Ordering[A]].compare(a, b)

这里, implicitly 用于检索我们想要的隐式值,一种类型之一 Ordering[A], ,哪个定义方法 compare(a: A, b: A): Int.

我们将在下面看到另一种方法。

视图界限和上下文界限如何实现?

鉴于它们的定义,视图界限和上下文界限都用隐式参数实现,这不足为奇。实际上,我显示的语法是真正发生的事情的句法糖。请参阅下面的他们如何脱糖:

def f[A <% B](a: A) = a.bMethod
def f[A](a: A)(implicit ev: A => B) = a.bMethod

def g[A : B](a: A) = h(a)
def g[A](a: A)(implicit ev: B[A]) = h(a)

因此,自然地,人们可以在其完整的语法中写下它们,这对于上下文范围特别有用:

def f[A](a: A, b: A)(implicit ord: Ordering[A]) = ord.compare(a, b)

视图范围是用什么?

视图范围主要用于利用 皮条客我的图书馆 在您想以某种方式返回原始类型的情况下,通过该模式将方法添加到现有类中。如果您不需要以任何方式返回该类型,则不需要绑定视图。

视图界用法的经典示例正在处理 Ordered. 。注意 Int 不是 Ordered, 例如,尽管存在隐式转换。前面给出的示例需要一个绑定的视图,因为它返回了未转换类型:

def f[A <% Ordered[A]](a: A, b: A): A = if (a < b) a else b

如果没有视图界限,此示例将无法正常工作。但是,如果我要返回另一种类型,那么我不再需要绑定的视图:

def f[A](a: Ordered[A], b: A): Boolean = a < b

在我将参数传递给 f, , 所以 f 不需要知道。

除了 Ordered, ,图书馆最常见的用法是处理 StringArray, ,是Java类,就像Scala收藏一样。例如:

def f[CC <% Traversable[_]](a: CC, b: CC): CC = if (a.size < b.size) a else b

如果一个人试图在没有视图界限的情况下执行此操作,则返回类型 String 将是一个 WrappedString (Scala 2.8),类似地 Array.

即使类型仅用作返回类型的类型参数,也会发生同一件事:

def f[A <% Ordered[A]](xs: A*): Seq[A] = xs.toSeq.sorted

上下文范围是用什么?

上下文范围主要用于已被称为 Typeclass模式, ,作为Haskell类型类的引用。基本上,这种模式通过通过一种隐式适配器模式提供功能来实现继承的替代方法。

经典的例子是Scala 2.8 Ordering, ,替换 Ordered 整个Scala库。用法是:

def f[A : Ordering](a: A, b: A) = if (implicitly[Ordering[A]].lt(a, b)) a else b

虽然通常会看到这样写的书:

def f[A](a: A, b: A)(implicit ord: Ordering[A]) = {
    import ord.mkOrderingOps
    if (a < b) a else b
}

利用其中的一些隐式转换 Ordering 这使传统的操作员风格。 Scala 2.8中的另一个示例是 Numeric:

def f[A : Numeric](a: A, b: A) = implicitly[Numeric[A]].plus(a, b)

一个更复杂的例子是新的收集用法 CanBuildFrom, ,但是已经有很长的答案,所以我在这里避免使用它。而且,如前所述,有 ClassManifest 用法,必须初始化没有具体类型的新数组。

带有类型模式的上下文更有可能由您自己的课程使用,因为它们可以分开关注,而视图界限可以通过良好的设计在您自己的代码中避免(主要用于绕过别人的设计) )。

尽管很长一段时间以来,但在2010年确实可以使用上下文界限,现在在Scala最重要的库和框架中在某种程度上发现了某种程度上。不过,其用法的最极端例子是Scalaz库,它将Haskell的许多力量带到了Scala。我建议阅读有关类型模式的阅读,以使其更熟悉它的所有使用方式。

编辑

感兴趣的相关问题:

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top