Почему 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