Ruby - 方法更改输入变量值

时间:2014-10-09 18:12:35

标签: ruby-on-rails ruby

我是Ruby的新手,我无法理解此方法中发生的事情。

我在Rails控制器中进行此调用 -

@arr = SomeClass.find_max_option(params[:x], @pos, params[:y], some_var)

我试图将值恢复为@arr,这已成功发生,但我对该方法中对 @pos 的操作也被撤回;当我仅尝试获取@pos的值时,@arr的值会发生变化。

这里有关于方法的更多细节

#before going into the method
 @pos = [a,b]

def self.find_max_option(x, pos, y, some_var)

pos.collect! { |element|
    (element == b) ? [c,d] : element
    }
  end

#new value of pos = [a, [c,d]] which is fine for inside in this method

... #some calculations not relevant to this question, but pos gets used to generate some_array

return some_array

但是当方法完成并返回控制器时,@pos的值现在也是[a,[c,d]]。

这里发生了什么?我认为pos将与@pos分开处理,并且该值不会被带回。作为一种解决方法,我刚刚在该方法中创建了一个新的局部变量,但我想知道这是怎么回事

#my workaround is to not modify the pos variable
pos_groomed = pos.collect { |element|
    (element == b) ? [c,d] : element
    }
  end

2 个答案:

答案 0 :(得分:3)

不使用collect!,而只使用collect(不使用!)。因此,将您的方法重写为:

def self.find_max_option(x, pos, y, some_var)
  pos.collect { |element|
    (element == b) ? [c,d] : element
  }
end

使用! collect版本时,您将使用块返回的值替换每个元素。但是,在使用collect 而不使用 !时,会创建一个新数组,并且调用collect的对象不会被更改。请参阅文档:

collect! vs collect

在方法名称的末尾使用!是Ruby中的常见做法。 This question是相关的,值得一看。

答案 1 :(得分:1)

您正在使用收集的破坏性版本。 破坏性方法更改调用方法的对象,而非破坏性方法返回新对象。

Ruby开发人员倾向于将这些方法称为“方法”,因为惯例是破坏性方法具有的!后缀。

pos.collect! # changes pos and returns pos
pos.collect  # creates a new object

您的解决方法仅适用,因为您使用非破坏性收集,而原始代码使用收集!

pos.collect do |element|
 (element == b) ? [c,d] : element
end

应该工作得很好。

关于为什么对象在方法之外发生变化:

在ruby中,当您将参数传递给方法时,实际上是将引用传递给对象。 因此,将数组传递给方法并不能复制,只需将引用传递给原始数组即可。 没有办法超越价值'但如果你真的需要,你可以用dup或clone自己创建一个副本。