Scala的类型约束 2014-12-24 14:00:49 在scala中可以通过隐式参数来进行类型约束。 先来看一串代码: ``` def test[T](i:T)(implicit ev: T <:< java.io.Serializable) { print("OK") } ``` 上述代码中的`<:<`表示T类型属于`java.io.Serializable`类型的子类。 类似的还有`=:=`,也就是说: ``` A =:= B //表示A类型等同于B类型 A <:< B //表示A类型是B类型的子类型 ``` 这个看上去很像操作符的=:= 和 <:<,实际是一个类,它在Predef里定义: ``` sealed abstract class =:=[From, To] extends (From => To) with Serializable sealed abstract class <:<[-From, +To] extends (From => To) with Serializable ``` 回到最初的代码块,隐式参数`ev`就是`T <:< java.io.Serializable`类型的,表示只有参数类型T是java.io.Serializable的子类型,才符合类型要求。 ## Type类型中的=:=和<:< 在Type类型中=:=和<:<属于方法。举例: ``` scala> typeOf[List[_]] =:= typeOf[List[AnyRef]] res4: Boolean = false scala> typeOf[List[Int]] <:< typeOf[Iterable[Int]] res1: Boolean = true ``` 对于第一行,相当于: typeOf[List[_]].=:=(typeOf[List[AnyRef]]) ## <:和<:<的区别 假设有如下代码: ``` def foo[A, B <: A](a: A, b: B) = (a,b) scala> foo(1, List(1,2,3)) res1: (Any, List[Int]) = (1,List(1, 2, 3)) ``` 传入第一个参数是Int类型,第二个参数是List[Int],显然这不符合 B <: A 的约束,编译器在做类型推导的时候,为了满足这个约束,会继续向上寻找父类型来匹配是否满足,于是在第一个参数被推导为Any类型的情况下,List[Int] 符合Any的子类型。 ``` def bar[A,B](a: A, b: B)(implicit ev: B <:< A) = (a,b) scala> bar(1,List(1,2,3)) <console>:9: error: Cannot prove that List[Int] <:< Int. ``` 通过隐式参数ev来证明类型时,编译器不会向上寻找父类,而是直接报错。 由此可见,在用 <: 声明类型约束的时候,不如用<:<更严格。 参考: <http://hongjiang.info/scala-type-contraints-and-specialized-methods/> 非特殊说明,均为原创,原创文章,未经允许谢绝转载。 原始链接:Scala的类型约束 赏 Prev Scala的self-type和依赖注入 Next 关于逆变与协变