1

鉴于此代码:

  trait S {
    def s: String
  }

  trait I {
    def i: Int
  }

  case class CC_S(s: String) extends S
  case class CC_I(i: Int) extends I
  case class CC_S_I(s: String, i: Int) extends S with I

  def combine(s: S, i: I): S with I = CC_S_I(s.s, i.i)

此测试成功:

Assert.assertEquals(CC_S_I("s", 1), combine(CC_S("s"), CC_I(1)))

(如何)我可以将 combine 方法泛型为具有类型参数的特征吗?即我想定义这样的东西:

  trait MyTrait[A,B] {
    def combine(a: A, b: B): A with B
  }

这样我就可以像这样使用它:

  class MyClass[A <: CC_S, B <: CC_I] extends MyTrait[A,B] {
    override def combine(s: A, i: B) = CC_S_I(s.s, i.i) //Note: this line does not compile...
  }

  Assert.assertEquals(CC_S_I("s", 1), new MyClass().combine(CC_S("s"), CC_I(1)))

更新。这将是一个更好的例子:

  class MyClass[A <: S, B <: I] extends MyTrait[A,B] {
    override def combine(s: A, i: B) = CC_S_I(s.s, i.i) //Note: this line does not compile...
  }

请参阅 Travis 的答案下的评论以查看答案。

4

1 回答 1

2

问题在于它CC_S_I实际上不是CC_Sor的子类型CC_I(尽管它是Sand的子类型I)。以下将起作用:

class MyClass extends MyTrait[S, I] {
  def combine(s: S, i: I): S with I = CC_S_I(s.s, i.i)
}

附带说明一下,如果您正在做很多此类事情,那么Shapeless库值得研究。它允许您combine非常通用地编写方法:

import shapeless._

def combine[A, B, C, AL <: HList, BL <: HList, CL <: HList](a: A, b: B)(implicit
  aIso: Iso[A, AL],
  bIso: Iso[B, BL],
  cIso: Iso[C, CL],
  p: PrependAux[AL, BL, CL]
): C = cIso from p(aIso to a, bIso to b)

现在你只需要一点样板:

implicit val ccsIso = Iso.hlist(CC_S.apply _, CC_S.unapply _)
implicit val cciIso = Iso.hlist(CC_I.apply _, CC_I.unapply _)
implicit val ccsiIso = Iso.hlist(CC_S_I.apply _, CC_S_I.unapply _)

And you can write:

scala> val x = combine[
     |   CC_S, CC_I, CC_S_I, String :: HNil, Int :: HNil, String :: Int :: HNil
     | ](CC_S("s"), CC_I(1))
x: CC_S_I = CC_S_I(s,1)

The enormous type annotation is unfortunately necessary with this formulation, but this should give you some idea of what's possible, and there are things you could do to make the usage cleaner.

于 2012-09-15T17:35:58.657 回答