Dotty无法推断具有抽象类型的类型参数特征的通用Scala函数的结果类型

问题描述 投票:2回答:2

简单的值层次结构

想象一下这个简单的特征Value,其中每个实现类都有一个类型为valueT

trait Value {
  type T
  def value: T
}

我们有两个不同的实现类,分别表示IntString值。

case class IntValue(override val value: Int) extends Value {
  override type T = Int
}

case class StringValue(override val value: String) extends Value {
  override type T = String
}

类型的值的安全选择

如果我们有List值,我们希望有一种类型安全的方式来选择特定类型的所有值。类Values及其伴随对象可以帮助我们做到这一点:

object Values {
  private type GroupedValues = Map[ClassTag[_ <: Value], List[Value]]

  def apply(values: List[Value]): Values = {
    val groupedValues: GroupedValues = values.groupBy(value => ClassTag(value.getClass))
    new Values(groupedValues)
  }
}

class Values private (groupedValues: Values.GroupedValues) {
  // Get a List of all values of type V.
  def getValues[V <: Value : ClassTag] = {
    val classTag = implicitly[ClassTag[V]]
    groupedValues.get(classTag).map(_.asInstanceOf[List[V]]).getOrElse(Nil)
  }

  def getValue[V <: Value : ClassTag] = {
    getValues.head
  }

  def getValueOption[V <: Value : ClassTag] = {
    getValues.headOption
  }

  def getValueInner[V <: Value : ClassTag] = {
    getValues.head.value
  }
}

所有这些在Scala 2.13和Dotty 0.20.0-RC1中都可以正常工作,因此具有混合值列表...

val valueList = List(IntValue(1), StringValue("hello"))
val values = Values(valueList)

…我们可以选择元素并将其返回为正确的类型-在编译时全部检查:

val ints: List[IntValue] = values.getValues[IntValue]
val strings: List[StringValue] = values.getValues[StringValue]

val int: IntValue = values.getValue[IntValue]
val string: StringValue = values.getValue[StringValue]

val intOption: Option[IntValue] = values.getValueOption[IntValue]
val stringOption: Option[StringValue] = values.getValueOption[StringValue]

val i: Int = values.getValueInner[IntValue]
val s: String = values.getValueInner[StringValue]

在Dotty中选择Option[T]作为值失败

但是,如果我们添加此函数以选择值作为其T类型(即IntString),并将其作为Option返回,]]]

class Values ... {
  ...
  def getValueInnerOption[V <: Value : ClassTag] = {
    getValues.headOption.map(_.value)
  }
}

…然后在Scala 2.13中一切正常:

val iOption: Option[Int] = values.getValueInnerOption[IntValue]
val sOption: Option[String] = values.getValueInnerOption[StringValue]

但是在Dotty 0.20.0-RC1中,它不会编译:

-- [E007] Type Mismatch Error: getValue.scala:74:29 
74 |  val iOption: Option[Int] = values.getValueInnerOption[IntValue]
   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |                             Found:    Option[Any]
   |                             Required: Option[Int]
-- [E007] Type Mismatch Error: getValue.scala:75:32 
75 |  val sOption: Option[String] = values.getValueInnerOption[StringValue]
   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |                                Found:    Option[Any]
   |                                Required: Option[String]

我们可以通过在getValueInnerOption中添加类型参数来解决该问题,该参数将返回类型和抽象类型T绑定在一起,并允许我们指定返回类型。

def getValueInnerOption[V <: Value {type T = U} : ClassTag, U]: Option[U] = {
  getValues.headOption.map(_.value)
}

不幸的是,这意味着我们将不得不在呼叫站点添加T的实际类型(即IntString),这很遗憾,因为它只是样板。

val iOption: Option[Int] = values.getValueInnerOption[IntValue, Int]
val sOption: Option[String] = values.getValueInnerOption[StringValue, String]

Dotty中的错误或怎么办?

似乎Dotty已经知道T的上限,但无法将该知识传播到函数的结果类型。如果尝试从String寻求IntValue,则可以看到此信息:

-- [E057] Type Mismatch Error: getValue.scala:75:39 
75 |  val wtf = values.getValueInnerOption[IntValue, String]
   |                                       ^
   |Type argument IntValue does not conform to upper bound Value{T = String} 

原始代码(没有类型参数U)是否可以在最终的Scala 3.0中使用,或者是否需要以其他方式编写?

一个简单的值层次结构,想象一下这个简单的特征值,其中每个实现类都有一个类型T的值。特征值{类型T def值:T}我们有两个不同的实现...

scala dependent-type dotty type-projection
2个回答
1
投票
然后

val iOption: Option[Int] = values.getValueInnerOption[IntValue] val sOption: Option[String] = values.getValueInnerOption[StringValue]

编译。

但是问题是我不确定(和getValueInner

应该是否有效。因为它们的推断返回类型涉及V#T(如果您输入错误的返回类型,则可以在错误消息中看到它们),并尝试显式指定它们会给出

V不是合法路径,因为它不是具体类型

(请参阅http://dotty.epfl.ch/docs/reference/dropped-features/type-projection.html

0
投票
© www.soinside.com 2019 - 2024. All rights reserved.