Created
September 22, 2014 02:07
-
-
Save k4200/c26ba194c9ff6e1343e7 to your computer and use it in GitHub Desktop.
コンパイルが通らない
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
abstract class C | |
case class C1() extends C | |
case class C2() extends C | |
trait Service[T <: C] { | |
def getFoo(): Option[T] | |
} | |
object Service { | |
// found : List[Option[Any]] | |
// required: List[Option[T]] | |
def getAllFoos(services: List[Service[_]]): List[Option[C]] = { | |
services.map(_.getFoo()) | |
} | |
} |
def getAllFoos[A <: C](services: List[Service[A]]): List[Option[C]]
これだと
object C1Service extends Service[C1] { def getFoo(): Option[C1] = None }
object C2Service extends Service[C2] { def getFoo(): Option[C2] = None }
があった時、
Service.getAllFoos(List(C1Service, C2Service))
が上手く行かないっぽいですね。
どうすればいいんだろう?
一応こうすればいけますが、意図が変わってる可能性ありますね。
abstract class C
case class C1() extends C
case class C2() extends C
trait Service[+T <: C] {
def getFoo(): Option[T]
}
object Service {
def getAllFoos(services: List[Service[C]]): List[Option[C]] = {
services.map(_.getFoo())
}
}
object C1Service extends Service[C1] { def getFoo(): Option[C1] = None }
object C2Service extends Service[C2] { def getFoo(): Option[C2] = None }
Service.getAllFoos(List(C1Service, C2Service))
もしくはこうか。
abstract class C
case class C1() extends C
case class C2() extends C
trait Service {
type T <: C
def getFoo(): Option[T]
}
object Service {
def getAllFoos(services: List[Service]): List[Option[C]] = {
services.map(_.getFoo())
}
}
object C1Service extends Service { type T = C1; def getFoo(): Option[C1] = None }
object C2Service extends Service { type T = C2; def getFoo(): Option[C2] = None }
Service.getAllFoos(List(C1Service, C2Service))
ポイントは trait Service[T <: C]
にした場合、 Service[C]
と Service[C1]
と Service[C2]
が全然関係ない型になってしまうので、統一的に扱えないって所ですね。
これを trait Service[+T <: C]
とすれば、Service[C1]
と Service[C2]
が Service[C]
のサブ型と見做せるようになるので Service[C]
として統一的に扱えるようになります。
また、型引数を止めて、抽象メンバ型でやれば、Service
という型は一つになるので、こちらも Service
で統一的に扱えるようになります。 type T = C1
が必要なのはこの場合ですね。
共変を使うか、抽象メンバ型を使うか、の判断基準としては、「C1に特化したServiceの型を扱いたいかどうか」になるかと思います。
共変を使うパターンであれば以下の様な、Cの各実装クラスに特化したサービスを型で表す事ができますが、抽象メンバ型を使う場合は、全てが Service
型になってしまうのでC1に特化した型を表現するのが難しくなります。
def foo(s: Service[C1]): C1 = ...
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
(他にも解決方法あるかも)