简体   繁体   English

具有特征匹配的Scala通用

[英]Scala generic with trait matching

Look at this code. 看这段代码。

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)
    }
  }
}

Stupid Scala compiler shows error here: 愚蠢的Scala编译器在这里显示错误:

Error:(22, 39) type mismatch; 错误:(22,39)类型不匹配; found : mix.type (with underlying type SomeMix) required: T with SomeMix case mix: SomeMix => processMix(mix) 找到:mix.type(具有基础类型SomeMix)必需:T与SomeMix大小写混合:SomeMix => processMix(mix)

It does not understand that expression I matching to SomeMix is already of type T. Ok lets help him. 我不了解我匹配SomeMix的表达式已经是T类型。好的,可以帮助他。 Changed code: 更改的代码:

   def process(t:T) = {
    t match {
      case mix: T with SomeMix => processMix(mix) // <---- warning here 
      case _ => processAsUsual(t)
    }
  }

Now it agrees that all is correct but show warning: 现在它同意一切正确,但显示警告:

Warning:(22, 17) abstract type pattern T is unchecked since it is eliminated by erasure case mix: T with SomeMix => processMix(mix) 警告:(22,17)抽象类型模式T未选中,因为它已通过擦除情况混合消除:T与SomeMix => processMix(mix)

Is any good way to avoid both error and warning here? 有什么好的方法可以避免错误和警告?

Scala compiler is not stupid. Scala编译器并不愚蠢。 You can't check t is instance of T with SomeMix because of type erasure. 由于类型擦除,您无法T with SomeMix检查t是T with SomeMix实例。 Instead of dynamic type dispatching try to use typeclasses with static dispatching. 代替动态类型分派,请尝试将类型类与静态分派一起使用。

For example 例如

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)

Like this? 像这样?

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)
    }
  }
}

You can do this at compile time like @ppressives proposed. 您可以像@ppressives建议的那样在编译时执行此操作。 If you really want to do this at runtime you should find a way to keep types there after compile time. 如果您真的想在运行时执行此操作,则应该找到一种在编译后将类型保留在那里的方法。 In Scala standard way to do this is TypeTags . 在Scala中,标准方法是TypeTags

Try 尝试

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

Check 校验

Pattern match of scala list with generics Scala列表与泛型的模式匹配

Pattern matching on generic type in Scala Scala中通用类型的模式匹配

Since, as you mention, it's definitely an instance of T , you can just suppress the unchecked warning: 正如您提到的,由于它肯定是T的实例,因此您可以取消取消选中的警告:

case mix: (T @unchecked) with SomeMix

Note that it's still unchecked and at runtime only tests that the matchee is an instance of SomeMix ; 需要注意的是它仍然泛滥,在运行时只测试了matchee是实例SomeMix ; if you change to eg 如果您更改为例如

def process(t: Any) = ...

you'll get bad results. 你会得到不好的结果。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM