Почему Scala for-loop (и внутренние) NumericRange ограничивается размером Int и как разрабатывать функциональные возможности?

Что стоит за ограничением размера NumericRange Int в понимании Scala for-loop? Возможно ли (без большой головной боли) расширить "для/Seqs" NumericRange, чтобы использовать Long (или что-то большее, чем Int.MaxValue)?

scala> for (i: Long <- 0L to 10000000000) {}

java.lang.IllegalArgumentException: 0 to 10000000000L by 1: "seqs cannot contain more than Int.MaxValue elements."
    at scala.collection.immutable.NumericRange$.count(NumericRange.scala:227)
    at scala.collection.immutable.NumericRange.numRangeElements(NumericRange.scala:53)
    at scala.collection.immutable.NumericRange.length(NumericRange.scala:55)
    at scala.collection.immutable.NumericRange.foreach(NumericRange.scala:73)
    at .<init>(<console>:19)
    at .<clinit>(<console>)
    at .<init>(<console>:11)
    at .<clinit>(<console>)
    at $print(<console>)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at scala.tools.nsc.interpreter.IMain$ReadEvalPrint.call(IMain.scala:704)
    at scala.tools.nsc.interpreter.IMain$Request$$anonfun$14.apply(IMain.scala:920)
    at scala.tools.nsc.interpreter.Line$$anonfun$1.apply$mcV$sp(Line.scala:43)
    at scala.tools.nsc.io.package$$anon$2.run(package.scala:25)
    at java.lang.Thread.run(Thread.java:680)

- Страница Спасибо заранее!

Ответ 1

Короткий ответ - это, по-видимому, "особенность" - по крайней мере, он работает как разработанный.

Как отметил @drexin, реализация "to" ограничена наличием диапазона Int. Однако...

Проблема заключается в том, что NumericRange [T].count(),.numRangeElements и .length() возвращают Int - независимо от того, что такое T. В этом случае это NumericRange [Long], где кажется немного неправильным считать count() ограниченным 31 битом, IMHO.
Однако...

Из просмотра Jira вопросов, похоже, работает как разработано. См., Например, SI-4370. Но для того, чтобы быть уверенным, что с этой точки зрения, я ввел SI-5619.

Ответ 2

В Scala нет для цикла, а для понимания. Он работает иначе, чем цикл. На самом деле ваше понимание доступно для перевода:

(0L to 10000000000).map { i => // (0L to 10000000000) == collection.immutable.NumericRange.inclusive(0L, 10000000000,1)
  // block
}

К ограничению не относится к пониманию, но в типе Seq, который не может содержать больше элементов Int.MaxValue. Если вам действительно нужен цикл 10000000000x, вы все равно можете использовать

var i = 0L
while(i < 10000000000) {
  // do stuff
  i+=1
}

Ответ 3

Методы size и length возвращают Int, поэтому было бы невозможно вернуть значение больше, чем Int.MaxValue. В Seq метод apply принимает Int, страдающий той же проблемой. Поэтому коллекции Scala, такие как коллекции Java, ограничены элементами Int.MaxValue.

Ответ 4

Вы не можете считать элементы до тех пор, пока их счетчик не будет соответствовать Int, потому что length объявлен как возвращаемый Int, но вот ярлык: вы можете создавать итераторы с любым фактическим размером, так как вы не пытаетесь их подсчитать.

scala> def longRange(first: Long, last: Long) = new Iterator[Long] {
    private var i = first
    def hasNext = i < last
    def next = {val r = i; i += 1; r}
}
longRange: (from: Long, to: Long)java.lang.Object with Iterator[Long]

scala> val lol = longRange(0, Long.MaxValue) map (x => x * x)
lol: Iterator[Long] = non-empty iterator

scala> lol drop 5 take 5 foreach println
25
36
49
64
81