什么是Scala上下文和视图范围? [英] What are Scala context and view bounds?

查看:75
本文介绍了什么是Scala上下文和视图范围?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

In a simple way, what are context and view bounds and what is the difference between them?

一些易于理解的例子也很棒!

Some easy-to-follow examples would be great too!

推荐答案

我认为已经有人问过这个问题,但是,如果这样,问题在相关"栏中不明显.因此,这里是:

I thought this was asked already, but, if so, the question isn't apparent in the "related" bar. So, here it is:

视图绑定是Scala中引入的一种机制,用于启用某些类型的A ,就好像是某种类型的B.典型的语法是这样的:

A view bound was a mechanism introduced in Scala to enable the use of some type A as if it were some type B. The typical syntax is this:

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

换句话说,A应该具有对B的隐式转换,以便人们可以在类型为A的对象上调用B方法.标准库(无论如何,在Scala 2.8.0之前)最常见的视图边界用法是Ordered,例如:

In other words, A should have an implicit conversion to B available, so that one can call B methods on an object of type A. The most common usage of view bounds in the standard library (before Scala 2.8.0, anyway), is with Ordered, like this:

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.

Because one can convert A into an Ordered[A], and because Ordered[A] defines the method <(other: A): Boolean, I can use the expression a < b.

请注意,视图范围已弃用,您应避免使用它们.

Please be aware that view bounds are deprecated, you should avoid them.

上下文边界是在Scala 2.8.0中引入的,通常与所谓的 type class pattern 一起使用,这是一种模拟Haskell类型类提供的功能的代码模式,尽管在更冗长的方式.

Context bounds were introduced in Scala 2.8.0, and are typically used with the so-called type class pattern, a pattern of code that emulates the functionality provided by Haskell type classes, though in a more verbose manner.

虽然视图绑定可以用于简单类型(例如,A <% String),但是上下文绑定要求使用参数化类型,例如上面的Ordered[A],但与String不同.

While a view bound can be used with simple types (for example, A <% String), a context bound requires a parameterized type, such as Ordered[A] above, but unlike String.

上下文绑定描述了一个隐式的 value ,而不是视图绑定的隐式 conversion .它用于声明对于某些A类型,存在可用的B[A]类型隐式值.语法如下:

A context bound describes an implicit value, instead of view bound's implicit conversion. It is used to declare that for some type A, there is an implicit value of type B[A] available. The syntax goes like this:

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

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

This is more confusing than the view bound because it is not immediately clear how to use it. The common example of usage in Scala is this:

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

由于与类型擦除和数组的非擦除特性有关的不可思议的原因,对参数化类型进行的Array初始化要求提供ClassManifest.

An Array initialization on a parameterized type requires a ClassManifest to be available, for arcane reasons related to type erasure and the non-erasure nature of arrays.

该库中另一个非常常见的示例稍微复杂一些:

Another very common example in the library is a bit more complex:

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

在这里,implicitly用于检索我们想要的隐式值,类型为Ordering[A],该类定义了方法compare(a: A, b: A): Int.

Here, implicitly is used to retrive the implicit value we want, one of type Ordering[A], which class defines the method compare(a: A, b: A): Int.

我们将在下面看到另一种方式.

We'll see another way of doing this below.

给定定义,使用隐式参数实现视图边界和上下文边界也就不足为奇了.实际上,我展示的语法是实际情况的语法糖.见下文他们如何脱糖:

It shouldn't be surprising that both view bounds and context bounds are implemented with implicit parameters, given their definition. Actually, the syntax I showed are syntactic sugars for what really happens. See below how they de-sugar:

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)

因此,自然地,人们可以用完整的语法编写它们,这对于上下文边界特别有用:

So, naturally, one can write them in their full syntax, which is specially useful for context bounds:

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

视图边界"有什么用?

视图范围主要用于利用 pimp my library 模式,通过该模式,您可以在想以某种方式返回原始类型的情况下向现有类添加"方法.如果不需要以任何方式返回该类型,则不需要视图绑定.

What are View Bounds used for?

View bounds are used mostly to take advantage of the pimp my library pattern, through which one "adds" methods to an existing class, in situations where you want to return the original type somehow. If you do not need to return that type in any way, then you do not need a view bound.

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

The classic example of view bound usage is handling Ordered. Note that Int is not Ordered, for example, though there is an implicit conversion. The example previously given needs a view bound because it returns the non-converted type:

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

没有视图边界,此示例将无法正常工作.但是,如果我要返回其他类型,则不再需要绑定视图:

This example won't work without view bounds. However, if I were to return another type, then I don't need a view bound anymore:

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

这里的转换(如果需要)发生在我将参数传递给f之前,因此f不需要了解它.

The conversion here (if needed) happens before I pass the parameter to f, so f doesn't need to know about it.

除了Ordered,库中最常见的用法是处理StringArray,它们是Java类,就像它们是Scala集合一样.例如:

Besides Ordered, the most common usage from the library is handling String and Array, which are Java classes, like they were Scala collections. For example:

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

如果尝试在没有视图边界的情况下执行此操作,则String的返回类型将是WrappedString(Scala 2.8),对于Array也是如此.

If one tried to do this without view bounds, the return type of a String would be a WrappedString (Scala 2.8), and similarly for Array.

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

The same thing happens even if the type is only used as a type parameter of the return type:

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

上下文边界有什么用?

上下文边界主要用于称为 typeclass pattern 的类型,作为对Haskell类型类的引用.基本上,该模式通过一种隐式适配器模式使功能可用,从而实现了继承的替代方法.

What are Context Bounds used for?

Context bounds are mainly used in what has become known as typeclass pattern, as a reference to Haskell's type classes. Basically, this pattern implements an alternative to inheritance by making functionality available through a sort of implicit adapter pattern.

经典示例是Scala 2.8的Ordering,它替换了整个Scala库中的Ordered.用法是:

The classic example is Scala 2.8's Ordering, which replaced Ordered throughout Scala's library. The usage is:

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

尽管您通常会看到这样写:

Though you'll usually see that written like this:

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:

Which take advantage of some implicit conversions inside Ordering that enable the traditional operator style. Another example in Scala 2.8 is the Numeric:

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

一个更复杂的示例是CanBuildFrom的新集合用法,但是对此已经有很长的答案,因此在此我将避免使用它.而且,如前所述,ClassManifest用法是初始化没有具体类型的新数组所必需的.

A more complex example is the new collection usage of CanBuildFrom, but there's already a very long answer about that, so I'll avoid it here. And, as mentioned before, there's the ClassManifest usage, which is required to initialize new arrays without concrete types.

与类型类模式绑定的上下文更有可能由您自己的类使用,因为它们可以实现关注点的分离,而通过良好的设计,可以避免在您自己的代码中使用视图边界(它通常用于解决问题)别人的设计).

The context bound with the typeclass pattern is much more likely to be used by your own classes, as they enable separation of concerns, whereas view bounds can be avoided in your own code by good design (it is used mostly to get around someone else's design).

尽管已经有很长时间了,但在2010年确实开始使用上下文边界,现在在大多数Scala最重要的库和框架中都有一定程度的使用.不过,使用它的最极端的例子是Scalaz库,它为Scala带来了Haskell的很多功能.我建议阅读Typeclass模式,以更熟悉使用它的所有方式.

Though it has been possible for a long time, the use of context bounds has really taken off in 2010, and is now found to some degree in most of Scala's most important libraries and frameworks. The most extreme example of its usage, though, is the Scalaz library, which brings a lot of the power of Haskell to Scala. I recommend reading up on typeclass patterns to get more acquainted with all the ways in which it can be used.

编辑

相关的感兴趣的问题:

  • A discussion on types, origin and precedence of implicits
  • Chaining implicits

这篇关于什么是Scala上下文和视图范围?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆