l.contain-6ren">
gpt4 book ai didi

scala - 为什么 Seq.contains 接受类型 Any 而不是类型参数 A?

转载 作者:行者123 更新时间:2023-12-03 22:52:58 27 4
gpt4 key购买 nike

例如:

scala> val l:List[String] = List("one", "two")
l: List[String] = List(one, two)

scala> l.contains(1) //wish this didn't compile
res11: Boolean = false

The various explanations of why things were done this way in Java在这里似乎不太适用,因为 Map 和 Set 确实实现了 contains 的类型安全版本和 friend 。有没有办法做一个类型安全的 contains在 Seq 上将其克隆到 Set 中?

最佳答案

问题是Seq在其类型参数中是协变的。这对于它的大部分功能来说很有意义。作为一个不可变的容器,它真的应该是协变的。不幸的是,当他们必须定义一个采用某些参数化类型的方法时,这确实会妨碍他们。考虑以下示例:

trait Seq[+A] {
def apply(i: Int): A // perfectly valid

def contains(v: A): Boolean // does not compile!
}

问题是函数的参数类型总是逆变的,而返回类型是协变的。因此, apply方法可以返回 A 类型的值因为 Aapply 的返回类型是协变的.然而, contains不能采用 A 类型的值因为它的参数必须是逆变的。

这个问题可以用不同的方式解决。一种选择是简单地制作 A一个不变的类型参数。这允许它在协变和逆变上下文中使用。但是,这种设计意味着 Seq[String]不会是 Seq[Any] 的子类型.另一种选择(也是最常用的一种)是使用局部类型参数,该参数由协变类型限定在下方。例如:
trait Seq[+A] {
def +[B >: A](v: B): Seq[B]
}

这个技巧保留了 Seq[String] <: Seq[Any]属性以及在编写使用异构容器的代码时提供一些非常直观的结果。例如:
val s: Seq[String] = ...
s + 1 // will be of type Seq[Any]
+的结果本例中的函数是 Seq[Any] 类型的值, 因为 Any是类型 String 的最小上限 (LUB)和 Int (换句话说,最不常见的父类(super class)型)。如果你仔细想想,这正是我们所期望的行为。如果您使用 String 创建一个序列和 Int组件,那么它的类型应该是 Seq[Any] .

不幸的是,这个技巧虽然适用于 contains 之类的方法。 , 产生了一些令人惊讶的结果:
trait Seq[+A] {
def contains[B >: A](v: B): Boolean // compiles just fine
}

val s: Seq[String] = ...
s contains 1 // compiles!

这里的问题是我们正在调用 contains方法传递类型 Int 的值. Scala 看到了这一点并试图推断 B 的类型这是 Int 的父类(super class)型和 A ,在这种情况下被实例化为 String .这两种类型的 LUB 是 Any (如前所示),以及 contains 的本地类型实例化将是 Any => Boolean .因此, contains方法似乎不是类型安全的。

这个结果对 Map 来说不是问题或 Set因为它们的参数类型都不是协变的:
trait Map[K, +V] {
def contains(key: K): Boolean // compiles
}

trait Set[A] {
def contains(v: A): Boolean // also compiles
}

所以,长话短说, contains由于函数类型的工作方式(参数类型是逆变的),协变容器类型上的方法不能被限制为仅获取组件类型的值。这实际上并不是 Scala 的限制或糟糕的实现,而是一个数学事实。

安慰奖是这在实践中真的不是问题。而且,正如其他答案所提到的,您始终可以定义自己的隐式转换,从而添加“类型安全” contains -like 方法,如果你真的需要额外的检查。

关于scala - 为什么 Seq.contains 接受类型 Any 而不是类型参数 A?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2078246/

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