【问题标题】:Extract type from kind从种类中提取类型
【发布时间】:2020-08-14 06:27:20
【问题描述】:

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

例如。

让我们定义一个Container 特征。

trait Container[T] {
  def contained: T
}

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

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]): _$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

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

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

【问题讨论】:

    标签: scala types traits type-alias higher-kinded-types


    【解决方案1】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-07-20
      • 1970-01-01
      • 2022-09-29
      • 2014-08-28
      • 2020-01-04
      • 2021-02-21
      • 2020-01-17
      • 2021-09-13
      相关资源
      最近更新 更多