【问题标题】:Why do Scala's index methods return -1 instead of None if the element is not found?如果找不到元素,为什么 Scala 的索引方法返回 -1 而不是 None?
【发布时间】:2012-12-31 23:40:47
【问题描述】:

我一直想知道为什么在 Scala 中用于确定集合中元素位置的各种索引方法(例如 List.indexOfList.indexWhere)返回 -1 以指示给定元素在集合,而不是更惯用的 Option[Int]。返回 -1 而不是 None 是否有一些特别的优势,或者这只是出于历史原因?

【问题讨论】:

  • 我的猜测是历史原因(即 Java)和 Scala 中很少使用索引因此人们不太关注这些函数的事实的结合。

标签: scala


【解决方案1】:

只是出于历史原因,但后来人们想知道历史原因是什么:历史是什么,为什么会变成这样?

直接历史记录是java.lang.String.indexOf 方法,它返回索引,如果没有找到匹配的字符,则返回-1。但这并不新鲜。如果在字符串中没有找到任何字符,Fortran SCAN 函数将返回 0,这与 Fortran 使用 1 索引的情况相同。

这样做的原因是字符串只有正长度,因此任何负长度都可以用作None 值,而无需任何装箱开销。 -1 是最方便的负数,就是这样。

如果编译器不够聪明,无法意识到所有装箱和拆箱以及一切都无关紧要,这可能会加起来。特别是,创建一个对象往往需要 5-10 ns,而函数调用或比较通常需要 1-2 ns,所以如果集合很短,创建一个新对象可能会有相当大的分数损失(如果你的内存已经被占用了,GC 有很多工作要做)。

如果 Scala 最初有一个了不起的优化器,那么选择可能会有所不同,因为人们只会用选项编写东西,这样更安全且不是特殊情况,然后相信编译器会将其转换为适当的高性能代码。

【讨论】:

    【解决方案2】:

    速度? (不确定)

    def a(): Option[Int] = Some(Math.random().toInt)
    def b(): Int = Math.random().toInt
    val t0 = System.nanoTime; (0 to 1000000).foreach(_ => a()); println("" + (System.nanoTime - t0))
    // 53988000
    val t0 = System.nanoTime; (0 to 1000000).foreach(_ => b()); println("" + (System.nanoTime - t0))
    // 49273000
    

    您还应该始终检查 Some(index) 中的索引

    【讨论】:

    • 您的示例和它下面的文本令人困惑,因为当它正确完成时,Some 不包含值
    • Some 实际上可以包含一个 Option 时,我是否应该检查 Noneindex < 0
    • 不,Some 不能包含
    • Math.random 比较贵,所以这里的开销看起来很小。
    【解决方案3】:

    还有一个好处是只返回一个Int 可以使用Java 的内置类型,而Option[Int] 需要将整数包装在Object 中。这意味着更差的速度(如@idonnie 所示)但也意味着更多的内存使用。

    虽然Option 非常适合作为通用工具(我经常使用它),但其他非价值演示也是如此。 Double.NaN 或空字符串是完全有效且有用的。

    使用Option 的好处之一是能够将其作为集合传递给for 循环等。如果您不太可能这样做,检查 -1 或 NaN 可能比匹配 None/Some 更简洁。

    【讨论】:

    • Scala 没有 for 循环,它有一个 for 理解,顺便说一句。不在集合上运行,而是在单子上运行。
    • 这是一个广阔的前景。谢谢
    猜你喜欢
    • 2017-04-30
    • 1970-01-01
    • 2011-09-05
    • 1970-01-01
    • 2011-10-19
    • 2013-05-30
    • 2016-07-24
    • 2019-05-08
    • 2021-03-21
    相关资源
    最近更新 更多