代码之家  ›  专栏  ›  技术社区  ›  Adrian keiter

范围对象抛出java.lang.StringIndexOutOfBoundsException

  •  1
  • Adrian keiter  · 技术社区  · 7 年前

    在下面的代码中,如预期的那样,第一行编译并执行时没有结果。第二个也会编译(不应该!),并抛出StringIndexOutOfBoundsException。为什么?

    scala> 3 to 4 foreach (_ => "a")
    
    scala> 3 to 4 foreach ("a")
    java.lang.StringIndexOutOfBoundsException: String index out of range: 3
      at java.lang.String.charAt(String.java:658)
      at scala.collection.immutable.StringLike.apply(StringLike.scala:56)
      at scala.collection.immutable.StringLike.apply$(StringLike.scala:56)
      at scala.collection.immutable.WrappedString.apply(WrappedString.scala:34)
      at scala.collection.immutable.WrappedString.apply(WrappedString.scala:34)
      at scala.collection.immutable.Range.foreach(Range.scala:158)
      ... 28 elided
    
    2 回复  |  直到 7 年前
        1
  •  2
  •   Luis Miguel Mejía Suárez    7 年前

    在代码片段中, "a" 实际上是一个函数。不相信我?我们一起去兔子洞吧。

    “a” 是一个 java.lang.String . 从Scala的角度来看,这种类型是。。。很无聊。所以Scala有一个 implicit conversion 到 WrappedString 键入代码正在调用的。现在,如果我们跟随父母的足迹,我们会看到

    WrappedString <: IndexedSeq[Char] <: immutable.Seq[Char] <: Seq[Char]
      <: PartialFunction[Int, Char] <: (Int) => Char
    

    包装 (Int) => Char . 我们可以从中看出这一点的理由 the docs for Seq

    查看序列的另一种方式是作为 PartialFunction 从…起 Int 值设置为序列的元素类型。这个 isDefinedAt 序列的方法为从 0 直到 length .

    所以一个字符串(事实上,任何序列)的行为就像一个函数,它接受一个整数索引并返回序列中的那个位置。因此,当您尝试获取字符串中的第三个(后来是第四个)位置时,您会得到一个错误。


    作为一条一般性的建议,我使用了一个非常方便的编译器选项来解释这一点。如果你把你要问的代码放在一个包在最小单例中的文件中,就像这样

    object A {
      3 to 4 foreach ("a")
    }
    

    然后使用“编译”它 scalac -print filename.scala . 您将看到类似这样的输出

    [[syntax trees at end of                   cleanup]] // test.scala
    package <empty> {
      object A extends Object {
        def <init>(): A.type = {
          A.super.<init>();
          RichInt.this.to$extension0(scala.this.Predef.intWrapper(3), 4).foreach(scala.this.Predef.wrapString("a"));
          ()
        }
      }
    }
    

    super 呼叫

    RichInt.this.to$extension0(scala.this.Predef.intWrapper(3), 4).foreach(scala.this.Predef.wrapString("a"));
    

    3 to 4 语法,然后在我们看到的行中 scala.this.Predef.wrapString ,表示 wrapString 我之前链接到的转换在这里被隐式调用。从那以后,你只需要看看超类,直到找到你想要的。

        2
  •  2
  •   jwvh    7 年前

    "a" 索引处没有任何元素 3 4 . 将字符串更改为 "abcde" foreach 到 map 看看结果。

    推荐文章