2017-02-02 8 views
0

У меня есть следующий код:Рубин цикла локальные переменные и inmutability

# Assuming each element in foo is an array. 
foo.each do |bar| 
    zaz = bar.first 
    # Other code using zaz, but not modifying it. 
end 

Будет zaz локальной переменной быть изменен на каждой итерации внутри этого цикла, что делает его изменчивым? Я не уверен в поведении Ruby здесь.

+0

Мой плохой, я имел в виду переменную zaz не foo. Я уже редактировал вопрос. – Navarro

+0

_ «сделать этот код изменчивым» _ - что вы имеете в виду? 'Array # first' не изменяет массив, и' zaz' никогда не используется. – Stefan

+0

Я не задал вопрос правильно, теперь я его исправил. Просто хотел знать, можно ли считать, что 'zaz' будет неспокойным. В моем реальном коде 'zaz' ссылается, но никогда не изменяется. – Navarro

ответ

1

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

foo.each do |bar| 
    # do something with element like 
    # print it, change it, save it 
end 

Функциональная alterantive является карта

foo.map { |bar| bar.something } 

Он возвращает новый массив, который исходный массив обрабатывается непреложным образом. Очевидно, вы должны быть осторожны, чтобы использовать непреложные методы.Это не было бы неизменно:

foo.map { |bar| bar.something! } 

Здесь something! делает что-то деструктивное к элементу массива. Однако я никогда не видел map. Используйте each для чего-то разрушительного.

+0

_ «Каждый цикл является разрушительным» - можете ли вы это объяснить? – Stefan

+1

'each' оценивает блок, но игнорирует его значение. Кроме того, 'каждый' просто возвращает свой приемник без изменений. Единственный возможный способ, при котором 'each' не просто не-op, - это если блок имеет побочный эффект. Просто посмотрите на множество вопросов о SO о том, «почему мой« ary.each do | i | i + 1 end »ничего не делает?» –

+0

Это то, что я искал. Большое спасибо за объяснение! – Navarro

4

Это действительно зависит от кода перед циклом.

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

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

Вы можете гарантировать, что zaz всегда рассматривается как блок локальной переменной и никогда не оглядывались в окружающем объеме, явным образом объявить его как блок локальной переменной в списке параметров блока:

foo.each do |bar; zaz| 
    zaz = bar.first 
end 

однако следует отметить, что ваш код имеет смысл только IFF код нечисто и изменяемые:

  1. Вы присвоить zaz, но никогда не использовать его внутри блока. Таким образом, единственный способ, что это имеет смысл вообще, - это то, что zaz является локальной переменной во внешней области, и вы назначаете ее. Хотя в этом случае весь цикл полностью эквивалентен zaz = foo.last.first.
  2. each оценивает блок только для его побочных эффектов. Без побочных эффектов each не имеет никакого смысла, поэтому тот факт, что вы используете each, подразумевает, что у вас есть побочные эффекты.

Обратите внимание, что термин «неизменный» без дополнительной квалификации, как правило, относится к значениям. Когда мы говорим о «неизменяемых переменных», мы обычно говорим «неизменяемая переменная» явно, чтобы четко указать, что мы говорим только о том, можно ли перегруппировать переменную, а не об изменении состояния объекта. Или можно просто сказать «постоянный», что является техническим термином «неизменяемой переменной» ... хотя этот термин уже имеет конкретное значение в Ruby.

+0

Я бы не сказал, что «константа» - это технический термин «неизменяемая переменная». С математической точки зрения, по крайней мере, константа - это то, что всегда имеет одно и то же значение (т. Е. В нескольких приложениях функций и т. Д.), Например, PI, которое всегда равно 3.14 .... Если у меня есть что-то вроде 'def f (x) y = x + 1; y * y end ", тогда как' x', так и 'y' являются неизменяемыми - я никогда их не переназначаю. Но они не являются константами в математическом смысле, потому что их значения могут быть разными каждый раз, когда применяется 'f'. В математической функции «f (x) = y^2, где y = x + 1',' x' и 'y' будут переменными, а не константами. – sepp2k