为什么地图/过滤器...不适用于无数数组?

问题描述:

是不是所有类型的子类型?为什么地图/过滤器...不适用于无数数组?

scala> val array = new Array(5) 
array: Array[Nothing] = Array(null, null, null, null, null) 

scala> array.map(_ => 42) 
<console>:9: error: value map is not a member of Array[Nothing] 
     array.map(_ => 42) 
      ^

scala> array.filter(_ != 42) 
<console>:9: error: value filter is not a member of Array[Nothing] 
     array.filter(_ != 42) 
      ^

这很奇怪,这是行不通的。

这是指定的功能还是错误?

当你看到涉及Nothing的奇怪行为时,这是因为类型推断算法认为它自己插入了Nothing,因为它是在类型推断期间引入的:如果对类型变量没有任何了解,则它由Any和Nothing限定。长久以来,我一直在列举一些事情来确定是否可以为此目的引入新的内部唯一底层类型,以便用户级别无与推理级别混合,但这是一项非常雄心勃勃的任务。尽管如此,我现在可能已经足够坚强来尝试它了。

我怀疑Scala不应该让你做那种Array[Nothing]实例化。根据定义,没有任何附近有任何实例,但是您的数组看起来像是用Nothing s填充,但是null不是Nothing的有效值。例如,这将失败,错误type mismatch; found : Null(null) required: Nothing

val n: Nothing = null 

所以我希望给每个你其实可以骗过系统,相信你终于得到的多寻求的Nothing例如保持时间遇到了麻烦......

这是另一个奇怪的情况。执行此操作:

object Main { 

    class Parametrized[T] { var value: T = _ } 

    def main(args: Array[String]) { 
    val p = new Parametrized // typed as Parametrized[Nothing] 
    val n = p.value // n is now actually an instance of Nothing... isn't it? 
    println(p.value) // prints null, but null is not an instance of Nothing 
    println(n)  // throws NullPointerException... 
    } 

} 
+0

'null'并不是真的'null',它更像是一个'throw new NullPointerException'。 'toString'有点误导。 – soc 2011-04-30 18:23:28

+0

@soc我意识到现在:编译器实际上通过抛出“unboxes”null作为Nothing。有趣的是,它并没有在上面的'println(p.value)'上做。 – 2011-05-02 07:47:46

请注意,Scala数组类型是不变的。因此Nothing是一切的一个子类型可能不相关。

另外mapfilter没有在Array上定义。 Predef中的隐式转换用于为数组提供此类方法。

因此,编译器无法找到从Array[Nothing]mapfilter定义的内容的隐式转换。使用REPL,我可以清楚地看到,这样的隐式转换应提供:

scala> val conv = implicitly[Array[Nothing] <%< collection.mutable.ArrayOps[Nothing]] 

conv: <%<[Array[Nothing],scala.collection.mutable.ArrayOps[Nothing]] = <function1> 

scala> conv(new Array[Nothing](5)).filter(_ => true) 
res8: Array[Nothing] = Array(null, null, null, null, null) 

于是问题就来了,为什么编译器不考虑genericArrayOps转换。

+0

在REPL中测试隐式转换是否可用的好方法! – 2011-04-30 18:30:55