【问题标题】:Why Scala compiler throws IndexOutOfBoundException while applying foreach on a mutable list为什么Scala编译器在对可变列表应用foreach时抛出IndexOutOfBoundException
【发布时间】:2015-05-02 14:54:09
【问题描述】:

我有以下代码。

import scala.collection.mutable.MutableList
val x = MutableList[Int]()
(1 to 10).foreach(x+=1)

我收到java.lang.IndexOutOfBoundsException: 1 错误。

但是,

(1 to 10).foreach(println) this does not throw any error.

indexOutOfBoundException 可以使用 lambda 运算符解决如下:

(1 to 10).foreach(_ => x+=1)

这一切都很好。

我的问题是:
1. 为什么我需要在第一种情况下使用 lambda 运算符而不是第二种情况?
2.为什么编译器会抛出IndexOutOfBoundException,我想这不是这个异常的正确上下文。

【问题讨论】:

    标签: scala collections


    【解决方案1】:

    发生的事情是图书馆里的一些小便利合谋咬你。

    foreach 签名是

    def foreach(f: A => Unit): Unit
    

    在你的例子中,AInt,所以它需要一个接受 Int 并返回 Unit 的函数。 println 很好。请注意,您刚刚写了println,而不是println(something),这不是一个函数。

    人们会认为 x += 1 只是一条指令,因此它的类型为 Unit,而不是函数,不是 foreach 的有效参数,并且会得到一个有用的编译时错误。但是MutableList中的+=实际上返回了列表,这很方便,因为它使链接操作更容易:

    def +=(elem: A): this.type
    

    所以 x+= 1 的类型是 MutableList[Int]。人们仍然会期望编译错误,而不是函数。除了MutableLists(实际上都是Seqs)是函数,带有 Int 参数,返回 Seq 元素的类型。该函数只返回第 i 个元素。同样,这可能很方便,您可以简单地将 seq 传递到预期函数的位置,而不必编写 i => seq(i)。现在你有了一个带有 Int 参数的函数,这是 foreach 所期望的。

    不过,它不返回 Unit,而是返回 Int。但是,scala 将接受它作为Int => Unit,只是丢弃该值。所以它编译。

    现在看看它的作用:首先,它评估 foreach 中的参数,所以它调用x+=1,得到列表 x,它现在包含一个元素。然后它会调用这个函数,这是对第 i 个元素的访问,参数范围是 1 到 10)。这样做,它不会向列表中添加值,而只是访问给定索引处的元素。然后它立即失败,因为列表只包含一个元素,索引为0,因此使用1 调用会抛出IndexOutOfBoundException

    【讨论】:

    • 哈哈。我永远也想不通。顺便说一句,这会提示编译器您正在尝试做什么:(1 to 10).foreach(_ => x+=1)
    猜你喜欢
    • 2020-08-22
    • 2017-10-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-28
    • 2011-01-04
    • 2015-01-25
    相关资源
    最近更新 更多