【scala类型系统】类型约束与特定方法

1. A类型等同于B类型

A =:= B

1.1 符号定义

sealed abstract class =:=[From, To] extends (From => To) with Serializable

1.2 符号说明

  1. =:=其实是中缀写法,可以看作From =:= To
  2. 父类From => To是Function[-From, +To]的另一种写法,相当于继承了trait Function1[-T1, +R],实例化需要实现Function1[-T, +R]中的apply方法
  3. 因为继承了Function[-From, +To],因此可以将 From =:= To看作是From => To的子类,遵循函数继承的规律:子类函数定义域大于父类,子类函数值域小于父类

2. A类型是B类型的严格子类型

A <:< B

2.1 符号定义

sealed abstract class <:<[From, To] extends (From => To) with Serializable

2.2 符号说明(略)

3. A可以当做B,即A为B的子类型或A可以隐式转换为B

A <%< B

4. 使用场景

4.1 <:<的使用

<:<符号必须使用柯里化函数在隐式参数中定义(带implicit前缀)

def test[T](i:T)(implicit ev: T <:< java.io.Serializable){println("ok")}
test("hi") // 正常
test(2) // 报错
  1. test方法中有一个隐式参数ev,类型为T <:< java.io.Serializable,表示参数类型T是java.io.Serializable的子类型
  2. 上下文中没有ev的定义,该隐式值由Predef提供
  3. private[this] final val singleton_<:< = new <:< [Any, Any]{def apply(x: Any):Any = x}
  4. implicit def conform[A]: A <:< A = singleton_<:<.asInstanceOf[A <:< A]
  5. 当调用test(“hi”)时,编译器推断出T是String,在寻找String <:< java.io.Serializable类型的隐式参数
  6. 上下文中找不到String <:< java.io.Serializable,于是通过conforms隐式方法产生一个
  7. conforms方法只有一个类型参数,他产生的结果是<:<[String, String]类型的对象
  8. 根据<:<抽象类的签名,<:<[-From, +To]第一个类型参数是逆变的,第二个参数是协变的
  9. 对<:<[-From, +To],子类的第一个参数要大于等于父类第一个参数的类型范围,子类的第二个参数要小于等于父类第二个参数的类型范围
  10. <:<[String,String]是<:<[String, java.io.Serializable]的子类
  11. 调用test(2)时,因为隐式方法产生的<:<[Int, Int]不符合<:<[Int, java.io.Serializable]子类型,抛出了异常

另外,对于Type类型,在判断之间的关系时也有类似的写法,不过这里是Type类型的方法:

typeOf[List[_]] =:= typeOf[List[AnyRef]] // false
typeOf[List[Int]] =:= typeOf[Iterable[Int]]  // true

4.2 <:<与<:的区别

4.2.1 A <: B的执行过程

根据较小的类A寻找一个合适的类作为上界,这个合适的类是B或B的父类,如果是B则说明是A的直接或间接父类,如果是B的父类,则说明B被向上强制转型

  1. 根据A类型,向上查找A类型的超类是否是B类型,若是,则结束,若否,则进行第2步
  2. 查看超类的其他直接子类中是否有B类型,若是,则结束,若否,则返回第1步继续查找
  3. 若上界为AnyVal,则A和B都是数值类型
  4. 若上界为AnyRef,则A和B都是容器类型(或自定义类型)
  5. 若上界为Any,则A和B分别是数值类型和容器类型(或自定义类型)
// 举例
class A 
class B extends A
class C extends A
def test[A, B <: A](a: A, b: B) = (a, b) // 我们返回(a, b)是为了更好的观察a和b的类型
test(new B, new C) // (A, C) = (B@3dd2a70d,C@7ecf001f),B被向上转型为父类A

4.2.2 A <:< B的执行过程

要求B必需是严格是A的父类或超类,不能是某个超类的子类,此时寻找B的过程相对简单,不断向上

  1. 根据A类型,向上查找A类型的超类是否是B类型,若是,则结束,若否,则递归进行第1步
  2. 若搜索达到定级类型仍未发现B类型,则报错
// 举例
class A
class B extends A
class C extends A
def test[A,B](a: A, b: B)(implicit ev: B <:< A) = (a, b)
test(new A, new C) // (A, C) = (A@29478556,C@2d0ea3a9),A为C的父类或超类
test(new B, new C) // 报错:error: Cannot prove that C <:< B,因为C向上搜索直至Any都没有找到B类型,因此报错
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

鱼摆摆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值