范围对象抛出java.lang.StringIndexOutOfBoundsException

时间:2019-02-06 18:18:11

标签: scala

在下面的代码中,第一行如期编译并没有结果执行。第二个也将编译(不应编译)并抛出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 个答案:

答案 0 :(得分:2)

因为字符串total在索引"a"或索引3上没有任何元素。将字符串更改为4,它将不会引发该错误。将"abcde"更改为foreach以查看结果。

答案 1 :(得分:2)

在您的代码段中,gem install bundler实际上是一个函数。不相信我吗?让我们一起去兔子洞吧。

"a""a"。从Scala的角度来看,这种类型非常无聊。因此Scala具有implicit conversion类型的WrappedString类型,您的代码正在调用该类型。现在,如果我们跟随父母的足迹,我们会看到

java.lang.String

因此WrappedString <: IndexedSeq[Char] <: immutable.Seq[Char] <: Seq[Char] <: PartialFunction[Int, Char] <: (Int) => Char 实际上是WrappedString的子类。我们可以在the docs for Seq

中看到其基本原理
  

查看序列的另一种方法是使用(Int) => Char中的PartialFunction   序列元素类型的值。 Int   序列的方法在从isDefinedAt0的时间间隔内返回true。

因此,字符串(实际上是任何序列)的行为都类似于一个函数,该函数采用单个整数索引并返回序列中的该位置。因此,当您尝试在字符串中获得第三个(随后是第四个)位置时,会出现错误。


作为一般建议,我使用一个非常方便的编译器选项对此进行了解密。如果您将代码放在一个最小单例包装的文件中,就像这样

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转换在这里被隐式调用。从那里开始,只需查看超类,直到找到所需的内容即可。