She*_*III 22 scala contains list covariance implicit-cast
List("a").contains(5)
Run Code Online (Sandbox Code Playgroud)
因为a Int永远不会包含在列表中String,所以这应该在编译时生成错误,但事实并非如此.
它浪费并默默地测试String列表中包含的每个内容的相等性5,这些内容永远不会成立(在Scala中"5"永远不等于5).
这被称为" '包含'问题 ".而一些人暗示,如果一个类型系统无法正确地输入这样的语义,那么为什么要经过强制执行类型的额外的努力.所以我认为这是一个需要解决的重要问题.
类型参数化B >: A的List.contains输入的任何类型的是该类型的超类型A(包含在列表中的元素的类型).
trait List[+A] {
def contains[B >: A](x: B): Boolean
}
Run Code Online (Sandbox Code Playgroud)
此类型参数化是必要的,因为+A声明列表在类型上是协变的A,因此A不能在逆变位置中使用,即作为输入参数的类型.协变列表(必须是不可变的)对于扩展比强制列表(可以是可变的)更强大.
A是String在上面的例子有问题,但Int不是的超类型String,所以发生了什么事?该隐含包容 Scala中,决定Any是两者的相互超String和Int.
Scala的创建者Martin Odersky 建议修复将限制输入类型B仅限于那些具有equals方法的类型Any.
trait List[+A] {
def contains[B >: A : Eq](x: B): Boolean
}
Run Code Online (Sandbox Code Playgroud)
但这并没有解决问题,因为两种类型(其中输入类型不是列表元素类型的超类型)可能具有相互超类型,它是子类型Any,也是子类型Eq.因此,它将编译没有错误,并且将保留错误键入的语义.
在每个地方禁用隐式包含也不是理想的解决方案,因为隐式包含是下面的例子为什么包含Any工作的原因.当接收站点(例如作为函数参数传递)为相互超类型(甚至可能不是Any)输入正确的语义时,我们不希望被强制使用类型转换.
trait List[+A] {
def ::[B >: A](x: B): List[B]
}
val x : List[Any] = List("a", 5) // see[1]
Run Code Online (Sandbox Code Playgroud)
所以我的问题是这个问题的最佳解决方案是什么?
我的初步结论是,应该在定义站点关闭隐式包含,否则语义不能正确输入.我将提供一个答案,显示如何在方法定义站点关闭隐式包含.有替代解决方案吗?
请注意,此问题是一般性的,不会与列表隔离.
更新:我已经提交了一个改进请求,并在此开始了一个scala讨论主题.我还在Kim Stebel和Peter Schmitz的回答中添加了评论,表明他们的答案有错误的功能.因此没有解决方案.同样在上述讨论主题中,我解释了为什么我认为soc的答案是不正确的.
soc*_*soc 12
这在理论上听起来不错,但在我看来在现实生活中分崩离析.
equals不是基于类型,contains而是建立在其之上.
这就是为什么代码1 == BigInt(1)工作并返回大多数人期望的结果的原因.
在我看来,制定contains更严格的条款是没有意义的equals.
如果contains会更严格,代码List[BigInt](1,2,3) contains 1就会完全停止工作.
顺便提一句,我认为"不安全"或"不安全"是正确的条款.
为什么不使用相等的类型类?
scala> val l = List(1,2,3)
l: List[Int] = List(1, 2, 3)
scala> class EQ[A](a1:A) { def ===(a2:A) = a1 == a2 }
defined class EQ
scala> implicit def toEQ[A](a1:A) = new EQ(a1)
toEQ: [A](a1: A)EQ[A]
scala> l exists (1===)
res7: Boolean = true
scala> l exists ("1"===)
<console>:14: error: type mismatch;
found : java.lang.String => Boolean
required: Int => Boolean
l exists ("1"===)
^
scala> List("1","2")
res9: List[java.lang.String] = List(1, 2)
scala> res9 exists (1===)
<console>:14: error: type mismatch;
found : Int => Boolean
required: java.lang.String => Boolean
res9 exists (1===)
Run Code Online (Sandbox Code Playgroud)
我认为我至少对这里发布的一些问题有一个合法的解决方案 - 我的意思是,问题是List("1").contains(1):
https://docs.google.com/document/d/1sC42GKY7WvztXzgWPGDqFukZ0smZFmNnQksD_lJzm20/edit
| 归档时间: |
|
| 查看次数: |
1162 次 |
| 最近记录: |