在Scala中返回参数化类型的子类

时间:2017-07-04 07:41:19

标签: scala

我正在尝试返回参数化类型Output[T <: Input]的子类但由于某种原因我似乎无法正确使用语法:

sealed trait Input
case class A(id: Int) extends Input
case class B(id: String) extends Input

sealed trait Output[+T <: Input]
case class OutA(some: String) extends Output[A]
case class OutB(thing: Int) extends Output[B]

def doStuff[T <: Input, RT <: Output[T]](input: T): RT = 
  input match {
    case A(i) => OutA(i.toString)
    case B(s) => OutB(s.toInt)
  }

// error: type mismatch;
//  found   : OutA
//  required: RT
//            case A(i) => OutA(i.toString)
//
// error: type mismatch;
//  found   : OutB
//  required: RT
//            case B(s) => OutB(s.toInt)

def doStuff[T <: Input](input: T): Output[T] = 
  input match {
    case A(i) => OutA(i.toString)
    case B(s) => OutB(s.toInt)
  }

// error: type mismatch;
//  found   : OutA
//  required: Output[T]
//            case A(i) => OutA(i.toString)

// error: type mismatch;
//  found   : OutB
//  required: Output[T]
//            case B(s) => OutB(s.toInt)

def doStuff[T <: Input, RT <: Output[_]](input: T): RT = 
  input match {
    case A(i) => OutA(i.toString)
    case B(s) => OutB(s.toInt)
  }

// error: type mismatch;
//  found   : OutA
//  required: RT
//            case A(i) => OutA(i.toString)

// error: type mismatch;
//  found   : OutB
//  required: RT
//            case B(s) => OutB(s.toInt)

在我的实际代码中,InputOutput子类被包装在我无法修改的容器中,输入也来自另一个我无法控制的系统。但是,这似乎是我能想到的最小的例子,我得到了相同的编译时类型错误。

如何解决我的问题?

1 个答案:

答案 0 :(得分:0)

你可以这样做(这是Scala中type class的一个例子,搜索这个术语会给你很多帖子解释模式):

case class StuffDoer[T](doStuff: T => Output[T])
object StuffDoer {
  implicit val ADoer: StuffDoer[A] = StuffDoer(x => OutA(x.id.toString))
  implicit val BDoer: StuffDoer[B] = StuffDoer(x => OutB(x.id.toInt))
  implicit val InputDoer: StuffDoer[Input] = StuffDoer {
    case a: A => ADoer.doStuff(a)
    case b: B => BDoer.doStuff(b)
  }
}

def doStuff[T](input: T)(implicit doer: StuffDoer[T]) = doer.doStuff(input)

(实际上,这个问题的某些变体会不时被问到,但是写答案比搜索以前的问题要快。)