我们用类型证明来实现一个联合类型(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来是实现联合类型,对比一下更简洁。
你好,我想请问一下,implicit ev: (Int with String) <:< A 这段代码是不是scala编译器编译后自动生成了一个由Int With String 的复合类型到泛型A的隐式值?
这个貌似不够强。 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
scala> f(1.23)
:9: error: Cannot prove that Int with String <: f(1.23:Any)
OK
之前没注意这个评论,可能是scala编译器bug?我在2.11.6下验证是没有问题的:
上边我的回复排版乱了。。。
scala> f(1.23)
:13: error: Cannot prove that Int with String <: f(1.23: Any)
OK
咦,这个编辑器貌似不是所见即所得。
关键点在于给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)都是可以的。