基于输入类型的Scala动态返回类型

时间:2020-01-15 22:16:16

标签: scala types pattern-matching

好吧,所以我不知道这段代码有什么问题:

import scala.reflect.runtime.universe._
trait Key extends Product
case class SomeKey(a: Int, b: String) extends Key
case class SomeOtherKey(a: Int, b: String, c:Boolean) extends Key

trait MyTrait[T <: Key] {
  def someField: Int
  def someFunc(implicit tTypeTag: TypeTag[T]): Map[T, Int] = {
    typeOf(tTypeTag) match {
      case t if t =:= typeOf[SomeKey] => Map(SomeKey(1,"2") -> 1)
      case t if t =:= typeOf[SomeOtherKey] => Map(SomeOtherKey(1,"2",true) -> 2)
    }
  }
}

如果从扩展Map[SomeKey, Int]的案例类中调用someFunc,我希望(示例已被简化)能够返回MyTrait[SomeKey]。然后从Map[SomeOtherKey, Int]

返回一个MyTrait[SomeOtherKey]
case class MyClass(val s: Int) extends MyTrait[SomeKey] {
  override def someField = s
}

这里,MyClass的新实例在调用Map[SomeKey, Int]时应返回someFunc

但是它甚至无法编译,编译器抱怨模式匹配的每一行:

type mismatch;
 found   : (Playground.this.SomeKey, Int)
 required: (T, Int)

type mismatch;
 found   : (Playground.this.SomeOtherKey, Int)
 required: (T, Int)

2 个答案:

答案 0 :(得分:4)

这是使用类型类和隐式的解决方案。

trait Key extends Product
case class SomeKey(a: Int, b: String) extends Key
case class SomeOtherKey(a: Int, b: String, c:Boolean) extends Key

trait TypeClass[T] {
  def someFunc: Map[T, Int]
}
object TypeClass {
  implicit def forSomeKey: TypeClass[SomeKey] = new TypeClass[SomeKey] {
    override def someFunc: Map[SomeKey, Int] = Map(SomeKey(1, "2") -> 1)
  }
  implicit def forSomeOtherKey: TypeClass[SomeOtherKey] = new TypeClass[SomeOtherKey] {
    override def someFunc: Map[SomeOtherKey, Int] = Map(SomeOtherKey(1, "2", true) -> 1)
  }
}

trait MyTrait[T <: Key] {
  def someField: Int
  def someFunc(implicit tc: TypeClass[T]): Map[T, Int] = tc.someFunc
}

答案 1 :(得分:3)

TypeTag会将类型信息转移到运行时,但是方法的返回类型是 compile-time 构造,因此会出现编译器错误。而是考虑通过扩展方法(但又被Luis的建议劫持了)

sealed trait Key
final case class SomeKey(a: Int, b: String) extends Key
final case class SomeOtherKey(a: Int, b: String, c: Boolean) extends Key

trait MyTrait[T <: Key]

trait KeyFactory[T <: Key] {
  def someFunc(): Map[T, Int]
}

object KeyFactory {
  def someFunc[T <: Key](implicit ev: KeyFactory[T]) = ev.someFunc
  implicit val someKeyFoo: KeyFactory[SomeKey] = () => Map(SomeKey(1,"2") -> 1)
  implicit val someOtherKey: KeyFactory[SomeOtherKey] = () => Map(SomeOtherKey(1,"2", true) -> 2)
}

implicit final class MyTraitKeyFactory[T <: Key : KeyFactory](private val v: MyTrait[T]) {
  def someFunc(): Map[T, Int] = implicitly[KeyFactory[T]].someFunc()
}

case class MyClass(s: Int) extends MyTrait[SomeKey]
case class MyOtherClass(s: Int) extends MyTrait[SomeOtherKey]


MyOtherClass(42).someFunc()
MyClass(11).someFunc()

输出

res0: Map[SomeOtherKey,Int] = Map(SomeOtherKey(1,2,true) -> 2)
res1: Map[SomeKey,Int] = Map(SomeKey(1,2) -> 1)