我是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
答案 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的对象不会被更改。请参阅文档:
在方法名称的末尾使用!
是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自己创建一个副本。