Подтвердить что ты не робот

Оператор параллельного присваивания в Ruby

Я читал пример из книги "Программирование в Рубине":

def fib_up_to(max)
  i1, i2 = 1, 1 # parallel assignment (i1 = 1 and i2 = 1)
  while i1 <= max
    yield i1
    i1, i2 = i2, i1+i2
  end
end
fib_up_to(100) {|f| print f, " " }

Это просто печатает числа Фибоначчи до 100. Это хорошо. Когда я заменяю параллельное назначение:

i1 = i2
i2 = i1+i2

Я не получаю желаемый результат.

Можно ли использовать параллельные назначения? Я исхожу из фона Java, и мне кажется странным видеть этот тип назначения.

Еще один вопрос: параллельное назначение оператора?

4b9b3361

Ответ 1

Проблема с выполнением задания в 2 отдельных операторах заключается в том, что i2 = i1 + i2 будет использовать новое значение i1, а не предыдущее значение, необходимое для правильной генерации последовательности Фибоначчи.

Когда вы используете параллельное назначение, все выражения с правой стороны сначала оцениваются, а затем назначаются принимающим переменным с левой стороны.

Параллельное назначение не является специальным оператором. По существу, то, что находится в правой части, действует как массив, где, если мы перечисляем несколько переменных в левой части, тогда массив распаковывается и назначается в соответствующие переменные.

Вот еще несколько примеров:

irb(main):020:0> a = 1, 2 # assign to a single variable
=> [1, 2]
irb(main):021:0> a
=> [1, 2]
irb(main):022:0> a, b = 1, 2 # unpack into separate variables
=> [1, 2]
irb(main):023:0> a
=> 1
irb(main):024:0> b
=> 2
irb(main):025:0> a, b = [1, 2, 3] # 3 is 'lost' as no receiving variable
=> [1, 2, 3]
irb(main):026:0> a
=> 1
irb(main):027:0> b
=> 2
irb(main):028:0> first, *rest = [1, 2, 3] # *rest consumes the remaining elements
=> [1, 2, 3]
irb(main):029:0> first
=> 1
irb(main):030:0> rest
=> [2, 3]

Это полезная функция ruby, например, она облегчает использование методов, возвращающих несколько значений, например.

def sum_and_difference(a, b)
  a + b, a - b
end

sum, difference = sum_and_difference 5, 3

В Java наиболее близким было бы иметь метод, который возвращал int[], но если бы мы хотели вернуть строку и число, нам нужно было бы создать небольшое POJO, чтобы действовать как struct для возвращаемого значения или return Object[] и загромождать код приложением. См. этот другой вопрос, который я ответил недавно для более практического примера.

Ответ 2

Я читал то же самое и имел тот же вопрос. Это было бы менее запутанным и имело бы больше смысла, если бы оно было написано так:

def fib_up_to(max)
  i1 = i2 = 1
  while i1 <= max
    yield i1
    i1, i2 = i2, i1+i2
  end
end

fib_up_to(100) {|f| print f, " " }

Использование i1, i2 = 1, 1 не имеет смысла, на мой взгляд. Но этот тип назначения имеет смысл для строки 5.