Scala通用性与trait匹配
Scala通用性与trait匹配
看这段代码。
trait SomeMix {
}
trait Processor[T] {
def processMix(t: T with SomeMix) = {
println("处理带有Mix的T")
}
def processAsUsual(t:T)= {
println("处理T")
}
def process(t:T) = {
t match {
case mix: SomeMix => processMix(mix) // <---- 这里有错误
case _ => processAsUsual(t)
}
}
}
愚蠢的Scala编译器在这里显示错误:
错误:(22, 39)类型不匹配;
找到:mix.type(具有底层类型SomeMix)
需要:T with SomeMix
case mix: SomeMix => processMix(mix)
它不明白我匹配到的SomeMix表达式已经是类型T了。好吧,让我们帮助他。修改代码:
def process(t:T) = {
t match {
case mix: T with SomeMix => processMix(mix) // <---- 这里有警告
case _ => processAsUsual(t)
}
}
现在它同意一切都正确了,但是显示警告:
警告:(22, 17)抽象类型模式T未经检查,因为它被擦除
case mix: T with SomeMix => processMix(mix)
有没有好的方法可以避免这里的错误和警告?
问题的出现原因是在trait Processor中的processMix方法只能处理T类型的参数,而不能处理SomeMix类型的参数。实际上,processMix方法调用了一些需要T和SomeMix功能的方法。
解决方法是将processMix方法的参数类型改为SomeMix,并在方法内部进行类型转换。代码如下:
trait Processor[T] { def processMix(mix: SomeMix) = { val t = mix.asInstanceOf[T] println("processing SomeMix") // 进行一些需要T和SomeMix功能的操作 } def processAsUsual(t:T)= { println("processing T") } def process(t:T) = { t match { case mix: SomeMix => processMix(mix) case _ => processAsUsual(t) } } }
Scala泛型与特质匹配的问题出现是因为类型擦除导致无法检查t是否是T with SomeMix
的实例。因此,我们需要使用静态分派的类型类(typeclasses)来替代动态类型分派。
举个例子:
trait SomeMix { def someMethod: String = "test2" } class SomeType def process[T](t: T)(implicit P: Process[T]): Unit = P.process(t) trait Process[T] { def process(t: T): Unit } implicit val processString: Process[SomeType] = s => println(s"processing $s as usual") implicit val processStringWithSomeMix: Process[SomeType with SomeMix] = s => println(s"processing $s with mix ${s.someMethod}") process(new SomeType) process(new SomeType with SomeMix)
感谢这个例子,它给了我一些新的想法。但是作为解决这个特定问题的方法并不好。处理的逻辑被移到了trait Process之外,这是不可接受的。但是也许我可以稍微修改一下以适应我的情况。
你可以将隐式参数processString和processStringWithSomeMix放到object Process中。在Scala中,将隐式参数的定义放在类型类的伴生对象中是一种常用的模式,这并不是将逻辑移到外部。