Инициализация val для использования в другом объеме - PullRequest
2 голосов
/ 03 февраля 2012

Как я могу инициализировать val, который будет использоваться в другой области?В приведенном ниже примере я вынужден сделать myOptimizedList как переменную, поскольку он инициализируется в области действия if (iteration == 5){} и используется в области действия if (iteration > 5){}.

val myList:A = List(...)
var myOptimizedList:A = null

for (iteration <- 1 to 100) {
    if (iteration < 5) {
        process(myList)
    } else if (iteration == 5)
        myOptimizedList = optimize(myList)
    } 
    if (iteration > 5) {
        process(myOptimizedList)
    }
}

Возможно, это было задано до , но мне интересно, есть ли элегантное решение, которое использует Вариант [A].

Ответы [ 4 ]

8 голосов
/ 03 февраля 2012

Кажется, что вы вынули этот пример кода из контекста, поэтому это решение может быть не очень подходящим для вашего реального контекста, но вы можете использовать foldLeft для его упрощения:

val myOptimizedList = (1 to 100).foldLeft (myList) {
    case (list, 5) => optimize(list)
    case (list, _) => process(list); list
}
3 голосов
/ 03 февраля 2012

Вы почти всегда можете переписать некую циклическую конструкцию в виде (хвостовой) рекурсивной функции:

@annotation.tailrec def processLists(xs: List[A], start: Int, stop: Int) {
  val next = start + 1
  if (start < 5) { process(xs); processLists(xs, next, stop)
  else if (start == 5) { processLists( optimize(xs), next, stop) }
  else if (start <= stop) { process(xs); processLists( xs, next, stop ) }
}
processLists(myList, 100, 1)

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

2 голосов
/ 03 февраля 2012

Существует еще один метод (возможно, уловка в этом случае) для задержки инициализации myOptimizedList, который заключается в использовании ленивого значения val.Ваш пример очень конкретный, но принцип по-прежнему очевиден, задерживайте присвоение значения val до первой ссылки.

val      myList          = List(A(), A(), A())
lazy val myOptimizedList = optimize(myList)

for (iteration <- 1 to 100) {
  if (iteration < 5)
    process(myList)
  else if (iteration > 5)
    process(myOptimizedList)
}

Обратите внимание, что регистр iteration == 5 игнорируется.

2 голосов
/ 03 февраля 2012

Часто бывает, что вы можете переделать свой код, чтобы избежать проблемы. Рассмотрим простой и распространенный пример:

var x = 0
if(something)
  x = 5
else
  x = 6
println(x)

Это был бы довольно распространенный шаблон в большинстве языков, но у Scala есть лучший способ сделать это. В частности, операторы if могут возвращать значения, поэтому лучше использовать следующий метод:

val x = 
  if(something)
    5
  else
    6
println(x)

Так что мы можем сделать x в конце концов.

Теперь, очевидно, ваш код можно переписать, чтобы использовать все val s:

val myList:A = List(...)
for (iteration <- 1 to 5)
  process(myList)
val myOptimizedList = optimize(myList)
for (iteration <- 5 to 100)
  process(myOptimizedList)

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...