1

假设我有一个 F 有界多态性状:

sealed trait FBound[Me <: FBound[Me]]
case class A() extends FBound[A]
case class B() extends FBound[B]

如果我有一个可以是任何实例的集合,我该如何使用它?

val canBeEither: Option[FBound[_]] = Some(B())

// error: type arguments [_$1] do not conform to trait FBound's type parameter bounds [Me <: FBound[Me]]
canBeEither.collect({ case b: B => b}).foreach(b => println("got a B!"))
4

2 回答 2

3

那将是

val canBeEither: Option[X forSome { type X <: FBound[X] }] = Some(B())

但我敦促您在代码中使用它之前三思而后行。它还会给你一堆关于存在类型的警告,你必须通过导入来静音scala.language.existentials

于 2019-01-25T15:40:47.763 回答
2

你会使用这种类型

T forSome { type T <: FBound[T] }
// equivalent
FBound[T] forSome { type T <: FBound[T] }

表示“某个FBound对象”。在你的情况下

val canBeEither: Option[T forSome { type T <: FBound[T] }] = Some(B())
canBeEither.collect { case b: B => b }.foreach(println)

您可能应该始终避免将活页夹拉出类型构造函数应用程序。例如List

val eithers: List[T forSome { type T <: FBound[T] }]
  = List[T forSome { type <: FBound[T] }](A(), B()) // ok
val eithers: List[T] forSome { type T <: FBound[T] }
  = List[ThereIsNothingThatCanGoHere](A(), B()) // not ok

所以你可能想说

type SomeFBound = T forSome { type T <: FBound[T] }

SomeFBound在任何地方使用。

于 2019-01-25T15:39:53.640 回答