Оператор параллельного присваивания в Ruby - PullRequest
18 голосов
/ 24 мая 2010

Я просматривал пример из книги «Программирование в 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, и мне очень странно видеть этот тип присваивания.

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

Ответы [ 2 ]

33 голосов
/ 24 мая 2010

Проблема с выполнением присваивания в 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, который будет действовать как структура для возвращаемого значения или возврата Object[] и загромождать код забросами. См. этот другой вопрос , на который я недавно ответил, для более практического примера.

2 голосов
/ 26 июня 2012

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

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.

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