gpt4 book ai didi

Scala 泛型类型推断与 ClassTag 不一致

转载 作者:行者123 更新时间:2023-12-02 03:16:53 32 4
gpt4 key购买 nike

我使用的是 Scala 2.10,发现在对泛型参数使用类型推断时出现了我认为很奇怪的行为。考虑下面的例子(注意 i 只是一个虚拟变量):

scala> import scala.reflect.{ClassTag,classTag}
|
| def broken[T : ClassTag](i : Int) : List[T] = {
| println("ClassTag is : " + classTag[T])
| List.empty[T]
| }

import scala.reflect.{ClassTag, classTag}

broken: [T](i: Int)(implicit evidence$1: scala.reflect.ClassTag[T])List[T]

scala> broken(3)
ClassTag is : Nothing
res0: List[Nothing] = List()

scala> val brokenVal : List[String] = broken(3)
ClassTag is : Nothing
brokenVal: List[String] = List()

调用 broken(3) 似乎是一致的,因为函数内的打印语句与推断的 ClassTag 一致。

但是,第二个语句,编译器为 ClassTag 推断并在函数内部打印的内容与实际返回类型之间存在不一致。

我希望编译器从类型声明中推断出 ClassTag,即 List[String]。这不对吗?谁能赐教一下?

这里有一些进一步的上下文:我实际上在一些代码中使用类标签来过滤集合(此处未显示),当我没有明确指定 T 时,它显然会失败,因为它是与 Nothing 类型进行比较。

最佳答案

第二个示例的实际返回 类型是List[Nothing],因此ClassTag 与它完全一致。发生这种情况是因为 List 是协变的(定义为 List[+A] 而不仅仅是 List[A])。这种协方差允许您编写类似 list = Nil 的语句(因为 Nil.type = List[Nothing]),但它也允许编译器将底部类型推断为列表类型参数,因为 List[Nothing]List[String] 的子类型,同样,由于它的协方差。所以实际的类型不匹配是在返回类型和 brokenVal 的类型之间。

为了克服这个限制,你可以使用不变类型作为你的返回类型,即:

import scala.reflect.ClassTag

class Invariant[T]

def f[T: ClassTag](i: Int): Invariant[T] = {
println("ClassTag: " + implicitly[ClassTag[T]])
new Invariant[T]
}

val ret: Invariant[String] = f(3)
// ClassTag: java.lang.String
// ret: Invariant[String] = Invariant@30af5b6b

另一方面,您可以让编译器从其他内容推断T,例如,通过传递类型T 的值作为参数。你不能让这个例子在普通 List 上工作,因为你不能改变它们的方差。

关于Scala 泛型类型推断与 ClassTag 不一致,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36456198/

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