首页 > 解决方案 > 从种类中提取类型

问题描述

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

例如。

让我们定义一个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] ... ]

Container为了解决这个重复问题,我尝试通过重新定义和ContainerExtractor来解决它

trait Container[T] {
  def contained: T
  final type Contained = T
}

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

这样(我希望)想要实现 a 的用户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]): _$2 (defined in trait ContainerExtractor);
found   : (container: Test.Container[String] with Test.Extra[Int])String
required: (container: Test.Container[String] with Test.Extra[Int])_$2

因为编译器无法推断通配符 in 引用的类型在此 trait 实现中C <: Container[_]是 a 。String

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

标签: scalatypestraitstype-aliashigher-kinded-types

解决方案


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

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

推荐阅读