如何 return scala中通用特征的子类型?

How to return subtype of a generic trait in scala?

我正在尝试创建一个工厂模式,return 类型是一个参数化特征,实际的 return 类型将是该特征的子类型,但我不知道泛型类型,所以我不知道如何指定 return 类型。简化版是这样的:

trait Mapper[T] {
    def createMap(a: T, b: T): T
}

class MapperA extends Mapper[String]{
    override def createMap(a: String, b: String): String = {
        a + b
    }
}

class MapperB extends Mapper[Int]{
    override def createMap(a: Int, b: Int): Int = {
        a + b + b + b
    }
}

def factory(typeOfMapper: String): Mapper = {
    typeOfMapper match {
        case "mapperA" => new MapperA()
        case "mapperB" => new MapperB()
    }
}

val mapper = factory("mapperA")

这会给我错误

trait Mapper takes type parameters

但我事先不知道通用类型。这里的 factory 方法的 return 类型应该是什么?

好吧,你可以 return Mapper[_] ... 这将编译,但并不是很有用,正如评论中指出的那样:你将无法使用return 以任何有意义的方式编辑值,因为 create 的实际类型是未知的。

如果映射器的不同实例总是具有不同的类型参数(至少在同一范围内),那么一个简洁的解决方案是使用隐式:

object Mapper { 
   implicit def strMapper: Mapper[String] = new MapperA
   implicit def intMapper: Mapper[Int] = new MapperB
}

然后在所有可见的地方,您可以这样做:

      val m1: Mapper[String] = implicitly[Mapper[String]] 
      val m2: Mapper[Int] = implicitly[Mapper[Int]]

你也可以这样写你的工厂函数(虽然,我不确定你为什么要这样做):

    def mapperFactory[T: Mapper] = implicitly[Mapper[T]]

并像这样使用它:

     val m: Mapper[String] = mapperFactory

或者像这样

    def intMapper = mapperFactory[Int]   

如果你想为相同类型的参数使用不同的映射器,这基本上是相同的想法,只是没有隐式看起来不那么整洁。关键是不同类型的不同工厂:

   class Mapper {
       def str(`type`: String): Mapper[String] = `type` match { 
         case "foo" => FooMapper()
         case "bar" => BarMapper()
       }
       def int(`type`: String): Mapper[Int] = `type` match {
          case "baz" => BazMapper()
          case "bak" => BakMapper()
       }
   }

   val fooMapper = Mapper.str("foo")
   val bakMapper = Mapper.int("bak")