先前在scala-user邮件列表中询问了此问题,但没有确认答案.
scala> val T = new Pair(1, 2){
override def equals(obj:Any) = obj.isInstanceOf[(Int, Int)] && obj.asInstanceOf[(Int, Int)]._1 == this._1}
}
T: (Int, Int) = (1,2)
scala> T match {
case (1, 1) => println("matched")
case _ => println("not matched")
}
not matched
scala> (1, 1) match {
case T => println("matched")
case _ => println("not matched")
}
not matched
scala> T == (1, 1)
res15: Boolean = true
Run Code Online (Sandbox Code Playgroud)
我认为常量(val)模式匹配结果取决于"等于"的返回值,但结果表明情况并非如此,那么标准是什么?
有人建议这case (1, 1) =>是一个提取器模式,Tuple2.unapply而是使用.所以我尝试了这些:
scala> Pair.unapply(T)
res1: Option[(Int, Int)] = Some((1,2))
scala> Pair.unapply(T).get == (1, 1)
res2: Boolean = true
Run Code Online (Sandbox Code Playgroud)
任何人都可以解释为什么==会成真,但我不能让它们匹配?
Fla*_*gan 13
您的示例的问题是您只覆盖equals您定义特定元组的匿名类的方法.让我们仔细看看你在运行这里给出的代码时正在做什么.
val p = new Pair(1, 2) {
override def equals(obj:Any) = {
obj.isInstanceOf[(Int, Int)] && obj.asInstanceOf[(Int, Int)]._1 == this._1
}
}
Run Code Online (Sandbox Code Playgroud)
Scala在这里做的是创建一个新的匿名类,它扩展Pair并覆盖它的等号.所以这相当于运行以下代码:
class Foo extends Pair(1,2) {
override def equals(obj:Any) = {
obj.isInstanceOf[(Int, Int)] && obj.asInstanceOf[(Int, Int)]._1 == this._1
}
}
val p = new Foo
Run Code Online (Sandbox Code Playgroud)
在这里,您可以确切地看到问题所在!定义equals不是对称的.p == (1,1)评估true和(1,1) == p评估false!这是因为前者相当于p.equals((1,1))后者相当于(1,1).equals(p).在您给出的示例中,它不起作用,因为案例中的对象与匹配的对象进行比较,而不是相反.因此,正如您所指出的那样,Pair.unapply(p).get == (1, 1)评估为true,但是(1,1) == Pair.unapply(p).get评估为false,并且似乎后者是匹配时使用的.
但是,在任何情况下,创建一个非对称的等号是一个非常糟糕的主意,因为代码的执行取决于您比较对象的顺序.此外,您定义的等于还有一个问题 - 它失败并出现错误当您尝试比较p与任何Pair这是没有类型的(Int, Int).这是因为,在类型擦除(这是JVM如何实现泛型)之后,a Pair不再由其组成部分的类型进行参数化.因此,(Int, Int)具有完全相同的类型(String, String),因此,以下代码将失败并出现错误:
p == ("foo", "bar")
Run Code Online (Sandbox Code Playgroud)
因为Scala会尝试投射(String, String)到(Int, Int).
如果你想实现这个功能,你可以做的最简单的事情是使用pimp我的库模式,拉皮条a Pair.但是,您不应该调用您的方法equals.称之为别的东西,比如~=.我现在必须要去,但是当我回来时,我可以给你代码.这很容易.你应该看equals一对中的实现并删除比较第二个参数的部分:)
通过#3888的决议,我可以对这个问题给出最终的答案。
T match { case (1, 1) =>
不,这与 无关unapply。正如临时提到的,case (1,1) =>是一个“元组模式”,是案例类 Tuple2 的“构造函数模式”的别名,它仅匹配构造为 Tuple2(1, 1) 或 Pair(1, 1) 的值。
真正关心的unapply是“提取器模式”:
object Pair {
val T = new Pair(1,1){
def unapply(p:(Int, Int)) :Boolean = this._1 == p._1
}
def main(args: Array[String]) = {
(1, 2) match {
case T() => println("matched")
case _ => println("not matched")
}
}
}
Run Code Online (Sandbox Code Playgroud)
你就“匹配”了。注意()in the case 子句
(1, 1) match { case T => ...
根据 scala 规范第 8.1.5 节,这是一个“稳定标识符模式”,case T匹配任何值 v 使得 T == v。所以我们应该“匹配”。“不匹配”的结果只是由当前编译器实现中的错误引起的。