这是 Scala 3 中的一个简短示例:
type Ext[S <: Seq[_]] = S match {
case Seq[t] => t
}
trait XX[A, B <: Seq[A]]
trait XX1[B <: Seq[_]] extends XX[Ext[B], B]
到目前为止它似乎是有效的,但是当与类型类结合时,面具开始剥落
implicitly[Ext[Seq[Int]] =:= Int] // e.scala: Cannot prove that e.Ext[Seq[Int]] =:= Int
可能是Scala type class & match types兼容性问题导致的。目前,避免这种情况的唯一方法似乎是不使用匹配类型。在 Scala 2 或 Scala 3 中有可能吗?
更新 1:我尝试了以下替代方法:
type Ext[S] = S match {
case Seq[t] => t
} // success!
type Ext[S <: Any] = S match {
case Seq[t] => t
} // success!
type Ext[S <: Seq[Any]] = S match {
case Seq[t] => t
} // same error
所以我相当确定这是一个错误。同样,问题是如何从一开始就避免使用匹配类型?
我在 Scala3 方面没有太多经验,但我猜你要找的是这个:
type Ext[S] = S match {
case Seq[t] => t
}
你不需要指定
S
是一个 Seq
,因为你不提供其他类型的选择器,你不能在编译时为 Seq
使用除 Ext
以外的其他类型:
implicitly[Ext[Option[String]] =:= String] // compile-time error
// selector Option[String] matches none of the cases
不确定这是否是一个错误,乍一看我是这样的,好吧,你正在匹配
S
(这是一种)与类型(即Seq[t]
),所以编译器无法证明你。但它仍然可以与种类相匹配:
type Ext[S <: Seq[_]] = S match {
case Vector[t] => t
case List[_] => String
}
implicitly[Ext[Vector[Float]] =:= Float]
implicitly[Ext[List[_]] =:= String]
看起来像个虫子。
匹配类型的替代方法是类型类
trait ExtTC[S]:
type Out
object ExtTC:
type Aux[S, Out0] = ExtTC[S] { type Out = Out0 }
given [S <: Seq[T], T]: Aux[S, T] = null
val ext = summon[ExtTC[Seq[Int]]]
summon[ext.Out =:= Int] // compiles
这对类型推断没有帮助
trait XX[A, B <: Seq[A]]
// doesn't compile: Type argument B does not conform to upper bound Seq[XX1.this.ext.Out]
trait XX1[B <: Seq[_]](using val ext: ExtTC[B]) extends XX[ext.Out, B]
但可以帮助隐式解决
trait XX[A, B](using B <:< Seq[A])
trait XX1[B <: Seq[_]](using val ext: ExtTC[B]) extends XX[ext.Out, B] // compiles