Для цикла в Scala без последовательности? - PullRequest
10 голосов
/ 08 сентября 2011

Итак, работая над «Scala для нетерпеливых», я подумал: а можно ли использовать цикл Scala for без последовательности?

Например, в книге есть упражнение, в котором вас попросят построить счетчик, который нельзя увеличить за Integer.MAX_VALUE.Чтобы протестировать свое решение, я написал следующий код:

var c = new Counter
for( i <- 0 to Integer.MAX_VALUE ) c.increment()

Это выдает ошибку: последовательности не могут содержать больше, чем элементы Int.MaxValue.Мне кажется, это означает, что Scala сначала выделяет и заполняет объект последовательности со значениями от 0 до Integer.MaxValue, а затем выполняет цикл foreach для этого объекта последовательности.

Я понимаю, что мог бы сделать это вместо этого:

var c = new Counter
while(c.value < Integer.MAX_VALUE ) c.increment()

Но есть ли способ сделать традиционный C-стиль цикла for с оператором for?

Ответы [ 4 ]

18 голосов
/ 08 сентября 2011

Фактически, 0 to N фактически не заполняет ничего целыми числами от 0 до N.Вместо этого он создает экземпляр scala.collection.immutable.Range, который применяет свои методы ко всем целым числам, сгенерированным на лету.

Ошибка, с которой вы столкнулись, заключается только в том, что вы должны соответствовать количеству элементов (независимо от того,они фактически существуют или нет) в положительную часть Int, чтобы поддерживать контракт для метода length.1 to Int.MaxValue отлично работает, как и 0 until Int.MaxValue.И последнее - то, что делает ваш цикл while (to включает в себя правильную конечную точку, until пропускает ее).

В любом случае, поскольку Scala for сильно отличается (намного более универсален)существо, чем C for, короткий ответ - нет, вы не можете делать то же самое.Но вы, вероятно, можете делать то, что вы хотите, с for (хотя, возможно, не так быстро, как вы хотите, так как есть некоторое снижение производительности).

5 голосов
/ 22 сентября 2011

Ничего себе, несколько хороших технических ответов на простой вопрос (что хорошо!) Но на тот случай, если кто-то просто ищет простой ответ:

//start from 0, stop at 9 inclusive
for (i <- 0 until 10){
    println("Hi " + i)
}

//or start from 0, stop at 9 inclusive
for (i <- 0 to 9){
    println("Hi " + i)
}

Как указал Рекс, слово «к» включаетправая конечная точка, «пока» не опускает.

4 голосов
/ 08 сентября 2011

Да и нет, это зависит от того, что вы просите. Если вы спрашиваете, можете ли вы выполнить итерацию последовательности целых чисел без необходимости сначала строить эту последовательность, то да, вы можете, например, с помощью потоков:

def fromTo(from : Int, to : Int) : Stream[Int] = 
  if(from > to) {
    Stream.empty
  } else {
    // println("one more.") // uncomment to see when it is called
    Stream.cons(from, fromTo(from + 1, to))
  }

Тогда:

for(i <- fromTo(0, 5)) println(i)

Написание собственного итератора путем определения hasNext и следующего - еще один вариант.

Если вы спрашиваете, можете ли вы использовать синтаксис 'for' для написания "собственного" цикла, то есть цикла, который работает путем увеличения некоторого собственного целого числа, а не итерации по значениям, генерируемым экземпляром объекта, тогда Ответ, насколько я знаю, нет. Как вы, возможно, знаете, 'for' - это синтаксический сахар для комбинации вызовов flatMap, filter, map и / или foreach (все они определены в признаке FilterMonadic ), в зависимости от вложенности генераторов и их типы. Вы можете попробовать скомпилировать некоторый цикл и вывести его промежуточное представление компилятора с помощью

scalac -Xprint:refchecks

чтобы увидеть, как они расширяются.

2 голосов
/ 08 сентября 2011

Там их куча, но я не могу потрудиться погуглить их сейчас. Следующее довольно канонично:

@scala.annotation.tailrec
def loop(from: Int, until: Int)(f: Int => Unit): Unit = {
  if (from < until) {
    f(from)
    loop(from + 1, until)(f)
  }
}

loop(0, 10) { i =>
  println("Hi " + i)
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...