scala类型系统:23) 用类型证明实现联合类型

我们用类型证明来实现一个联合类型(union type):

// 让参数类型满足Int或String

scala> def f[A](a: A)(implicit ev: (Int with String) <:< A) = println("OK")
f: [A](a: A)(implicit ev: <:<[Int with String,A])Unit

scala> f(2) 
OK

scala> f("hi")
OK

跟我们之前通过context bound来是实现联合类型,对比一下更简洁。

scala类型系统:23) 用类型证明实现联合类型》上有8个想法

  1. 你好,我想请问一下,implicit ev: (Int with String) <:< A 这段代码是不是scala编译器编译后自动生成了一个由Int With String 的复合类型到泛型A的隐式值?

  2. 这个貌似不够强。 AnyVal和Any类型都可以被接受。而且,如果我希望同时能够接受Int和String的子类,这个就不行了。

    • 代码如下:
      scala> def f[A](a: A)(implicit ev: (Int with String) <:< A) = println("OK")
      f: [A](a: A)(implicit ev: <: f(2)
      OK

      scala> f(“hi”)
      OK

      scala> f(1.23)
      :9: error: Cannot prove that Int with String <: f(1.23:Any)
      OK

  3. 之前没注意这个评论,可能是scala编译器bug?我在2.11.6下验证是没有问题的:

    
    
        scala> def f[A](a: A)(implicit ev: (Int with String) <:< A) = println("OK")
        f: [A](a: A)(implicit ev: <:<[Int with String,A])Unit
    
    
        scala> f(1.2)
        :9: error: Cannot prove that Int with String <:< Double.
                  f(1.2)
                   ^
    
    
    • 上边我的回复排版乱了。。。
      scala> f(1.23)
      :13: error: Cannot prove that Int with String <: f(1.23: Any)
      OK

  4. 咦,这个编辑器貌似不是所见即所得。
    关键点在于给1.23指定类型为Any之后就能编译通过了。
    说到底是因为Int with String是一个交集类型,而S <:< T表示S严格是T的子类型。所以这里这里要满足Int with String <:< A的条件,只需要找一个Int with String的父类型就能通过了,而Int with String的父类型包括Int, String, AnyVal, Any, AnyRef。所以f(1); f("haha"); f(1.23: AnyVal); f(1.23: Any); f(List(1, 2, 3): AnyRef)都是可以的。

发表评论

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