gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-04 10:57:12 25 4
gpt4 key购买 nike

一个简单的值层次结构

想象一下这个简单的特征 Value每个实现类都有一个 value某种类型 T .

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我们希望有一种类型安全的方式来选择特定类型的所有值。类(class) 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]

选择一个值作为 Option[T] Dotty 失败

但是,如果我们添加这个函数来选择值作为它们的 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 中工作,还是需要以不同的方式编写?

最佳答案

在 Dotty 尝试 match types作为类型投影的替代品

type InnerType[V <: Value] = V match {
case IntValue => Int
case StringValue => String
}

trait Value {
type This >: this.type <: Value
type T = InnerType[This]
def value: T
}

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

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

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

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

关于scala - Dotty 无法推断具有抽象类型的类型参数特征的泛型 Scala 函数的结果类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59101681/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com