如何将元组的扩展类型传递给不变的泛型函数?

How to pass extential type of tuple to invariant generic function?

我有一个扩展类型的元组,我想将它传递给一个泛型函数(我在这个例子中使用了 ClassTag,但它是一个自定义类型 class,具有不变的类型参数):

type TC = (ClassTag[T], Option[T]) forSome {type T}
def foo[T](ct: ClassTag[T], o: Option[T]) = {}

val tc: TC = (classTag[String], Option[String](null))
foo(tc._1, tc._2)

这给我错误:

error: type mismatch; found : scala.reflect.ClassTag[T] required: scala.reflect.ClassTag[Any] Note: T <: Any, but trait ClassTag is invariant in type T. You may wish to investigate a wildcard type such as _ <: Any. (SLS 3.2.10) foo(tc._1, tc._2)

我想确保两个参数的类型 cto 使用相同的参数类型 T 我认为扩展类型应该确保这一点,但它似乎不起作用。

然而,如果我不使用元组而只使用 ClassTag,它工作正常:

type TC = ClassTag[T] forSome {type T}
def foo[T](ct: ClassTag[T]) = {}

val tc: TC = classTag[String]
foo(tc)

所以之前ClassTag不变性的错误没有意义

为什么我使用元组时不起作用?我怎样才能让它发挥作用?

因为 val tc: TC = classTag[String], Option[String](null)) tc._1 有类型 ClassTag[_] (不同于任何 ClassTag[T] 例如 ClassTag[Any] 因为 ClassTag 是不变的), tc._2 的类型为 Option[_],与 Option[Any] 相同,因为 Option 是协变的

implicitly[Option[_] =:= Option[Any]]
implicitly[Option[Any] =:= Option[_]]

An existential type forSome { } where </code> contains a clause type <code>[tps]>:<: is equivalent to the type ′ forSome { } where results from </code> by replacing every covariant occurrence of <code> in </code> by <code> and by replacing every contravariant occurrence of in </code> by <code>.

https://www.scala-lang.org/files/archive/spec/2.13/03-types.html#existential-types

所以在

def foo[T](ct: ClassTag[T], o: Option[T]) = {}
foo(tc._1, tc._2)

类型不匹配。 Any_(又名任意 T)是不同的类型。

尝试使用通用量化而不是存在

type TC[T] = (ClassTag[T], Option[T])
def foo[T](ct: ClassTag[T], o: Option[T]) = {}

val tc: TC[String] = (classTag[String], Option[String](null))
foo(tc._1, tc._2)