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)))

(どのように) 型パラメーターを持つトレイトとして結合メソッドをジェネリックにすることができますか? つまり、次のように定義したいと思います。

  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

問題は、実際にはorCC_S_Iのサブタイプではないということです (ただし、andのサブタイプです)。以下が機能します。CC_SCC_ISI

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)

残念ながら、この定式化では巨大な型注釈が必要ですが、これにより、何が可能かについてのアイデアが得られるはずであり、使用法をより明確にするためにできることがいくつかあります。

于 2012-09-15T17:35:58.657 に答える