鉴于此代码:
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)))
(How)我可以将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...
}
请参阅特拉维斯回答的评论,以便看到答案。
答案 0 :(得分:2)
问题只是CC_S_I
实际上不是CC_S
或CC_I
的子类型(尽管它是S
和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 _)
你可以写:
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)
不幸的是,这种配方需要使用巨大的类型注释,但这应该可以让您了解什么是可能的,并且您可以采取一些措施来使用清洁。