我能否复制Scala的“==”行为?

4
在《Scala编程》一书中,我可以读到==运算符的行为就像是定义如下:
final def == (that: Any): Boolean = if (null eq this) {null eq that} else {this equals that}

但是,为了避免空指针异常,必须有编译器魔法,对吗?有没有办法用纯Scala复制这种行为;即,如果接收者为null,则返回一种东西,如果不是,则返回另一种东西?我的意思是一个实际的null eq this实现。

我想我可以编写一个“pimp”,然后在包装类上定义方法,但有没有更直接的方法来做到这一点?

6个回答

2

我不这么认为。据我所知,null没有什么神奇的东西。

(请参见更新)

我认为最好的方法是将任何对象包装成选项,这样您就可以使用许多有用的功能:

implicit def toOption[T](target: T) = Option(target)

val q: String = null
val q1: String = "string"

println(q getOrElse "null") // prints: null
println(q1  getOrElse "null") // prints: string

更新

我找到了这份文档:

http://www.scala-lang.org/api/2.7.7/scala/Null.html

根据该文档:

类 Null 与类 Nothing 一起位于 Scala 类型层次结构的底部。

因此,即使是 null,也继承了来自 AnyRef 的方法,例如 eq== 等等... 并且您也可以使用它们:

val q: String = null
val q1: String = "string"

println(null eq q) // prints: true
println(null eq q1) // prints: false

必须有一些魔法:尝试定义一个类似于 == 的方法并在 null 指针上调用它:你会得到一个 NullPointerException。但使用 == 则不会。 - Jean-Philippe Pellet
@JPP:请查看更新。是的,它变成了某种魔法...就像“Nothing”一样神奇。 - tenshi
谢谢更新。确实有一些魔法 - 所以我不能复制它,对吧? - Jean-Philippe Pellet
1
@JPP:我不这么认为,但您可以随时编写您的[编译器插件](http://www.scala-lang.org/node/140):) - tenshi
2
一个编译器插件,以某种方式消除 null。 - Monkey
@Monkey:是啊,那会很棒!@JPP,我们鼓励你编写这样的插件——我们都将永远感激你!但目前我们都应该尽量多使用“选项”…… - tenshi

2

似乎没有办法在不特殊处理null的情况下完成此操作。如果对象为null,Java不允许调用方法。相比之下,Python中的None是一个合适的对象。我认为最好的做法是尝试忽略null存在的事实。

使用隐式转换来模拟==

class Equals2(v:AnyRef){
  def ===(that:AnyRef) =  if(v eq null) {that eq null }else {v equals that}
}
implicit def equals2(v:AnyRef) = new Equals2(v) 

很不幸,以下代码无法正常工作,因为null不是AnyRef的子类。

null === "Something"

我同意。即使是 implicit def equals2(v:Null) = new Equals2(v) 也不起作用。我不确定为什么。我猜 null 只是不能隐式转换。虽然显式调用 equals2 函数也可以正常工作,即使没有 equals2(v:Null) 的重载。 - Ken Bloom

2

"null"是一个叫做Null的特质的唯一实例 - 因此它只是一个普通对象,没有魔法可以调用==

你应该绝对检查Option,并尽一切可能让nulls远离你的代码 :)


它似乎不是一个普通的对象。Trait Null 从 AnyRef 继承 hashCode,对吧?但试着在 null 上调用 hashCode:NPE。所以 eq、== 和其他操作需要编译器魔法。 - Jean-Philippe Pellet
NPE对我来说并不是什么神奇的东西 - 在Null类上实现hashCode应该会抛出NPE。如果hashCode不存在,那么它将是一个编译错误,而不是NPE。 - Adam Rabung

2
没有针对null的魔法,但是Scala确实有一些魔法可以使数字的相等性变得对称。这个技巧是通过扩展ScalaNumber特质来实现的...

http://www.scala-lang.org/node/6387

更新:
只是为了澄清一下......这意味着,如果你写了 a == b,而 b 派生自 ScalaNumber 或者(我相信)是一个 AnyVal,那么编译器将测试 b == a
这不仅解决了 null 的情况,而且如果你想将原始类型与可以视为数字的其他类型进行比较,但隐式转换会带来极大的不安全性,这也使事情变得更加容易。这是例如 BigInteger 所使用的方法。

1

nullNull 的唯一实例,因此在 Scala 中是一个完整的对象。

如果您按照上面在类 A 中发布的方式定义函数,则只需提供从 NullA 的隐式转换,将 null 映射到某个虚拟实例即可。


好的。所以,没有隐式转换就做不到。这就是我需要知道的全部。谢谢! - Jean-Philippe Pellet

0

你可以使用选项。

scala> Option("a")
res0: Option[java.lang.String] = Some(a)

scala> Option(null)
res1: Option[Null] = None

我想在我的自定义类上定义一个方法,在该方法中可以实现对类型 this eq null 的检查,而不会出现 NPE。 - Jean-Philippe Pellet
1
要明确的是,这个 eq null 永远不会导致空指针异常。 - Monkey
你能举个例子说明你在寻找什么吗? - Monkey

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接