具有特征匹配的 Scala 泛型
Scala generic with trait matching
看看这段代码。
trait SomeMix {
}
trait Processor[T] {
def processMix(t: T with SomeMix) = {
println("processing T with Mix")
}
def processAsUsual(t:T)= {
println("processing T")
}
def process(t:T) = {
t match {
case mix: SomeMix => processMix(mix) // <---- error here
case _ => processAsUsual(t)
}
}
}
愚蠢的 Scala 编译器在此处显示错误:
错误:(22, 39) 类型不匹配;
发现:mix.type(底层类型为 SomeMix)
要求:T 与 SomeMix
案例组合:SomeMix => processMix(mix)
不明白匹配SomeMix的表达式I已经是T类型了,好吧,帮帮他吧。更改代码:
def process(t:T) = {
t match {
case mix: T with SomeMix => processMix(mix) // <---- warning here
case _ => processAsUsual(t)
}
}
现在同意一切正确但显示警告:
警告:(22, 17) 抽象类型模式 T 未选中,因为它已被擦除消除
案例组合:T with SomeMix => processMix(mix)
这里有什么既可以避免错误又可以警告的好方法吗?
像这样?
trait SomeMix {
}
trait Processor[T] {
def processMix(t: SomeMix) = {
println("processing 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
的实例。尝试使用带有静态调度的类型类而不是动态类型调度。
例如
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)
您可以像@ppressives 建议的那样在编译时执行此操作。
如果您真的想在运行时执行此操作,您应该找到一种在编译后保留类型的方法。在 Scala 中,执行此操作的标准方法是 TypeTags.
尝试
import reflect.runtime.universe.{TypeTag, typeOf}
def typ[A: TypeTag](a: A) = typeOf[A]
def process(t: T)(implicit ev: TypeTag[T with SomeMix], ev1: TypeTag[T]) = {
t match {
case mix if typ(t) <:< typeOf[T with SomeMix] => processMix(mix.asInstanceOf[T with SomeMix])
case _ => processAsUsual(t)
}
}
val p = new Processor[Int] {}
p.process(10) //processing T
val p1 = new Processor[Int with SomeMix] {}
val ten = 10.asInstanceOf[Int with SomeMix]
p1.process(ten) //processing T with Mix
检查
Pattern match of scala list with generics
Pattern matching on generic type in Scala
因为,正如您提到的,它绝对是 T
的一个实例,您可以只抑制未经检查的警告:
case mix: (T @unchecked) with SomeMix
请注意,它仍未选中,并且在运行时仅测试匹配项是 SomeMix
的实例;如果您更改为例如
def process(t: Any) = ...
你会得到不好的结果。
看看这段代码。
trait SomeMix {
}
trait Processor[T] {
def processMix(t: T with SomeMix) = {
println("processing T with Mix")
}
def processAsUsual(t:T)= {
println("processing T")
}
def process(t:T) = {
t match {
case mix: SomeMix => processMix(mix) // <---- error here
case _ => processAsUsual(t)
}
}
}
愚蠢的 Scala 编译器在此处显示错误:
错误:(22, 39) 类型不匹配; 发现:mix.type(底层类型为 SomeMix) 要求:T 与 SomeMix 案例组合:SomeMix => processMix(mix)
不明白匹配SomeMix的表达式I已经是T类型了,好吧,帮帮他吧。更改代码:
def process(t:T) = {
t match {
case mix: T with SomeMix => processMix(mix) // <---- warning here
case _ => processAsUsual(t)
}
}
现在同意一切正确但显示警告:
警告:(22, 17) 抽象类型模式 T 未选中,因为它已被擦除消除 案例组合:T with SomeMix => processMix(mix)
这里有什么既可以避免错误又可以警告的好方法吗?
像这样?
trait SomeMix {
}
trait Processor[T] {
def processMix(t: SomeMix) = {
println("processing 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
的实例。尝试使用带有静态调度的类型类而不是动态类型调度。
例如
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)
您可以像@ppressives 建议的那样在编译时执行此操作。 如果您真的想在运行时执行此操作,您应该找到一种在编译后保留类型的方法。在 Scala 中,执行此操作的标准方法是 TypeTags.
尝试
import reflect.runtime.universe.{TypeTag, typeOf}
def typ[A: TypeTag](a: A) = typeOf[A]
def process(t: T)(implicit ev: TypeTag[T with SomeMix], ev1: TypeTag[T]) = {
t match {
case mix if typ(t) <:< typeOf[T with SomeMix] => processMix(mix.asInstanceOf[T with SomeMix])
case _ => processAsUsual(t)
}
}
val p = new Processor[Int] {}
p.process(10) //processing T
val p1 = new Processor[Int with SomeMix] {}
val ten = 10.asInstanceOf[Int with SomeMix]
p1.process(ten) //processing T with Mix
检查
Pattern match of scala list with generics
Pattern matching on generic type in Scala
因为,正如您提到的,它绝对是 T
的一个实例,您可以只抑制未经检查的警告:
case mix: (T @unchecked) with SomeMix
请注意,它仍未选中,并且在运行时仅测试匹配项是 SomeMix
的实例;如果您更改为例如
def process(t: Any) = ...
你会得到不好的结果。