从种类中提取类型

Extract type from kind

我想提取一种类型,并用它来定义函数的return类型。

例如

让我们定义一个 Container 特征。

trait Container[T] {
  def contained: T
}

让我们定义一个 Extra 特征,这样我们就可以从我们的容器中扩展它。

trait Extra[T] {
  def extra: T
}

让我们定义一个特征 ContainerExtractor

trait ContainerExtractor[T, C <: Container[T]] {
  def extract(container: C): T
}

现在用户可以通过

实现ContainerExtractor
new ContainerExtractor[String, Container[String] with Extra[Int]] {
  override def extract(container: Container[String] with Extra[Int]): String = ???
}

不错,虽然用户需要在Container里面声明类型两次! [String, Container[String] ... ]

为了解决这个重复问题,我尝试通过将 ContainerContainerExtractor 重新定义为

来解决这个问题
trait Container[T] {
  def contained: T
  final type Contained = T
}

trait ContainerExtractor[C <: Container[_]] {
  def extract(container: C): C#Contained
}

这样(我希望)想要实现 ContainerExtractor 的用户可以写:

new ContainerExtractor[Container[String] with Extra[Int]] {
  override def extract(container: Container[String] with Extra[Int]): String =???
}

虽然这失败了:

incompatible type in overriding
def extract(container: Test.Container[String] with Test.Extra[Int]): _ (defined in trait ContainerExtractor);
found   : (container: Test.Container[String] with Test.Extra[Int])String
required: (container: Test.Container[String] with Test.Extra[Int])_

因为编译器无法推断 C <: Container[_] 中通配符所引用的类型是此特征实现中的 String

关于如何避免用户在实施时定义容器类型两次的任何帮助 ContainerExtractor

使用 Class#T 的类型投影给出了 Class 的通用成员类型,而不是 Class 实例。在你的情况下,如果你只是做 C#Contained,它只是指 C 的成员类型。编译器不知道 C 是什么。您应该从变量中获取成员类型:

trait ContainerExtractor[C <: Container[_]] {
  def extract(container: C): container.Contained
}