首页 文章

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

提问于
浏览
102

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

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

4 回答

  • 15

    你找到了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
    }
    
  • 97

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

    在Scala中,View Bound( A <% B )捕获了'can be seen as'的概念(而上限 <: 捕获了'is a'的概念) . 上下文绑定( A : C )表示关于类型的'has a' . 您可以阅读有关清单的示例“ TManifest ” . 您链接到 Ordered vs Ordering 的示例说明了差异 . 一个方法

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

    说该参数可以看作 Ordered . 与之比较

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

    表示该参数具有关联的 Ordering .

    在使用方面,需要花费一些时间来 Build 约定,但是上下文边界优于视图边界(view bounds are now deprecated) . 一个建议是,当您需要将隐式定义从一个范围转移到另一个范围而不需要直接引用它时,首选上下文绑定(这对于用于创建数组的 ClassManifest 来说肯定是这种情况) .

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

  • 37

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

    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
    
  • 135

    这是另一个括号内容 .

    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) }
    

相关问题