scala类型系统:12) view bounds

很早前在来往的扎堆里发过一段模拟C#的using代码:

def using[ C <: { def close(): Unit }, T ] (resource: C) (handle: C => T): T = {
    try {
        handle(resource)
    } finally {
      closeQuietly(resource)
    }
}

Eric(药师)看到后,说 <% 更好

<%的意思是“view bounds”(视界),它比<:适用的范围更广,除了所有的子类型,还允许隐式转换过去的类型

def method [A <% B](arglist): R = ...

等价于:

def method [A](arglist)(implicit viewAB: A => B): R = ...

或等价于:

implicit def conver(a:A): B = …

def method [A](arglist): R = ...

<% 除了方法使用之外,class声明类型参数时也可使用:

scala> class A[T <% Int]
defined class A

但无法对trait的类型参数使用 <%

scala> trait A[T <% Int]
<console>:1: error: traits cannot have type parameters with context bounds `: ...' nor view bounds `<% ...'

补充,注意上面 using 方法中声明的结构类型 {def close():Unit},它的实现是通过反射做到的,所以有一定性能问题,在需要考虑性能的场景下,这里明确的用 java.io.Closeable 接口更合适,灵活性与性能你总要做一个选择。

scala类型系统:12) view bounds》上有5个想法

  1. Pingback引用通告: scala雾中风景(14): trait的泛型参数为何不支持context bounds | 在路上

  2. hongjiang您好!提一点我自己的看法,有错误的话请您指正:
    您在这篇博文中提到:

    def method [A B): R = …

    或等价于:

    implicit def conver(a:A): B = …

    def method [A](arglist): R = …

    我觉得您这篇博文这样描述是不是欠妥,关于def method [A <% B](arglist): R = …,它不出错的前提条件是A是B的子类型或者A能够隐式转换到B,否则method方法是存在问题的。而在后面两种方式里您已经写明了存在A到B的隐式转换,因此这两种method自然不会出现问题。因此我觉得用"等价"这个词是不是不合适?给人的感觉是def method [A <% B](arglist): R = …会自己生成A到B的隐式转换一样….接触Scala没多久,我的理解有问题请指正,谢谢。

    • 你理解是正确的,我没注意到那块的表述容易让初学者引起歧义(那个隐式转换不一定存在,当A不是B的子类时,view bound会去检查上下文是否存在A到B的隐式转换。)并不是等价于显示的增加了一个隐式转换。谢谢指正。

  3. 请您能不能指教一个问题,在定义了函数func1(a: Serializable){},调用函数func1(1)为何能成功?不知道在什么地方定义有Int到Serializable的隐式转换?

    • java.lang.Integer 类型继承自 java.lang.Number,Number这个抽象类是实现了 java.io.Serializable 接口的

发表评论

电子邮件地址不会被公开。 必填项已用*标注