【scala类型系统】内部类与模式匹配

1. 问题的引出:内部类中模式匹配出错

trait A {
    case class B(i: Int)
}

class C extends A {
    def !(a: Any) = a match{
    case B(0) => println("never be here") // 未匹配到:这里的B(0)类型为C#B和
    case b: B => println("never be here2") // 未匹配到:这里的B类型为C#B
    case B => println("never be here3") // 未匹配到:这里的B类型为C#B
    case x => println(s"received $x") // 匹配:匹配任意情形
    }
}

class D extends A{
    new C ! B(0) // 这里的B(0)类型为D#B
}

2. 路径依赖导致的模式匹配问题

2.1 问题1:

两个不同子类分别实例化继承的内部case类,将会产生两个不同的对象,路径依赖导致无法模式匹配

// case类自动实现了equals方法,在进行模式匹配时,equals主要对比构造函数的参数是否相等
case class X(i: Int)
new X(0) == new X(0) // true
// 对内部类的case类而言,需要考虑路径依赖问题
trait A{case class X(i: Int)}
class C extends A
class D extends A
val c = new C
val d = new D
val x1 = new c.X(0) // 类型为c.X
val x2 = new d.X(0) // 类型为d.X
val x3 = new d.X(0) // 类型为d.X
x1 == x2 // false:不同的外部对象,对应的内部case类是不同的
x2 == x3 // true:路径依赖相同

2.2 问题2:

case类自动生成伴生对象,两个不同子类中继承的case类的伴生对象,是两个不同的对象,路径依赖导致无法模式匹配

trait A{case class B(i: Int)}
class C extends A
class D extends A
val b1 = (new C).B // 类型为C#B
val b2 = (new D).B // 类型为D#B
b1 == b2 // false:不同的外部,对应的内部对象是不同的

3. 解决方案

3.1 解决方案1:

内部case类的实例化和使用放在同一上下文

trait A{case class B(i: Int)}
class C extends A{
    def foo(a: Any) = a match {
    case B(0) => println("never be here")
    case b: B => println("never be here2")
    caes B => println("never be here3")
    case x => println("received")
    }

    foo(B(0)) // 参数中的B(0)和模式匹配中的B(0)、b:B、B处于统一上下文,类型一致,可以匹配
}

3.2 解决方案2:

使用类型投影进行匹配[外部类]#[内部类]#[内部类的内部类]…

trait A{case class B(i: Int)}
class C extends A {
    def !(a: Any) = a match{
    case b: C#B => println("C#B") // 可以匹配
    case b: D#B => println("D#B") // 可以匹配
    case b: A#B => println("A#B") // 可以匹配
    case _ => println("-1")
    }
}

3.3 解决方案3:

使用同一对象通过new关键字实例化case类B,调用同一对象的!方法进行模式匹配

trait A{case class B(i: Int)}
class C extends A{
    def !(a:Any) = a match {
    case B(0) => println("match B(0)")
    case _ => println("-1")
    }
}

class D extends A{
    val c = new C
    val b = new c.B(0) // 根据路径依赖,这里的b的类型为c.B
    c ! b // 根据路径依赖此时c的!函数中的B(0)也为c.B类型,两个B为同一路径,可以完成匹配
// new C ! b不能匹配,因为new C产生的对象与c不是同一对象,因此与b路径依赖不同,无法匹配
}

new D
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

鱼摆摆

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

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

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

打赏作者

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

抵扣说明:

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

余额充值