在 Scala 中测试数组是否为空

Testing an array for emptiness in Scala

问题不在于如何 测试数组是否为空(arr.length == 0 可以做到这一点)。相反,我的问题是,为什么

scala> Array().isEmpty
res1: Boolean = true

工作和

scala> val x = Array[String]()
x: Array[String] = Array()
scala> x.isEmpty
res2: Boolean = true

工作,但是

scala> val y = Array()
y: Array[Nothing] = Array()

scala> y.isEmpty
<console>:13: error: value isEmpty is not a member of Array[Nothing]
       y.isEmpty
         ^

不会吧?

编辑:这个答案可能不正确。但我将其保留在这里以展示我是如何尝试调查此问题的。对我来说,这看起来像是编译器中的错误。

答案是 Array[T <: AnyRef] 存在的隐式转换 字符串是 AnyRefNothing 不是 AnyRef.

你怎么会自己发现这个?

在 IntelliJ 中,您可以在 isEmpty 下方看到一条灰色下划线

这意味着方法isEmpty不是Array的方法,而是隐式的(class上的方法,从Array进行了隐式转换)。

现在,要发现隐式转换,只需单击 ctrl+q

所以当你跟着它的时候,你就到了源代码中的这一行-

  implicit def refArrayOps[T <: AnyRef](xs: Array[T]): ArrayOps[T]    = new ArrayOps.ofRef[T](xs)

这解释了当 T 扩展 AnyRef

时隐式转换是在 Array[T] 上

所以回到我们的案例- String <: AnyRef,但这不适用于 Nothing

正如@MichaelZajac 指出的那样,Nothing 是一切的子类型(它的对应物 Any 是一切的超类型)。特别是它也是 AnyRef 的子类型。事实上,还有一个更通用的 genericArrayOps ,它根本没有类型限制(例如 Array[Any]().isEmpty 有效)!允许您使用 isEmpty 的隐式转换应该 开始,但当然不会,即使显式调用转换很好。

@slouc 给出的 link 就是答案,即 Scala 编译器在进行隐式解析时以特殊方式处理 Nothing,因为 Nothing 是 a 的默认下限进行类型推断时键入。

现在为什么不希望在隐式解析中考虑 NothingNothing 的棘手之处在于它是所有内容的子类型。这意味着如果 Scala 在任何时候将类型推断为 Nothing,则每个隐式转换都会立即生效。这可能会隐藏类型错误(你永远不应该有 Nothing 的实例,但是当 Nothing 变成 Int 时……谁说的好呢?)。 (请注意,我希望真正破解编译器的人能够参与其中 confirm/deny/elaborate)