Ruby on rails Ruby方法更改输入变量值

Ruby on rails Ruby方法更改输入变量值,ruby-on-rails,ruby,Ruby On Rails,Ruby,我是Ruby新手,我很难理解这个方法中发生了什么 我在Rails控制器中进行此调用- @arr = SomeClass.find_max_option(params[:x], @pos, params[:y], some_var) 我试图将该值返回给@arr,这是成功的,但我在该方法中对@pos所做的操作也被带回;当我仅尝试获取@arr的值时,@pos的值会发生变化 下面是有关该方法的更多详细信息 #before going into the method @pos = [a,b] def

我是Ruby新手,我很难理解这个方法中发生了什么

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

@arr = SomeClass.find_max_option(params[:x], @pos, params[:y], some_var)
我试图将该值返回给@arr,这是成功的,但我在该方法中对@pos所做的操作也被带回;当我仅尝试获取@arr的值时,@pos的值会发生变化

下面是有关该方法的更多详细信息

#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
而不是使用collect!,只需使用collect而不必使用!。因此,将您的方法重写为:

def self.find_max_option(x, pos, y, some_var)
  pos.collect { |element|
    (element == b) ? [c,d] : element
  }
end
当使用时!在collect版本中,您将使用块返回的值替换每个元素。但是,当使用collect with!,创建一个新数组,并且调用collect的对象不会被更改。见文件:

vs


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

您使用的是破坏性版本的collect。 破坏性方法更改调用该方法的对象,而非破坏性方法返回新对象

Ruby开发人员倾向于将这些方法称为“bang方法”,因为传统的做法是破坏性方法具有相同的功能!后缀

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自己创建副本

您将@pos作为参数传递,这意味着pos是对@pos的引用。您可以在collect之前设置pos=pos.dup!或者只是使用非破坏性收集。你的代码不是很直截了当,因为你返回的是一个不存在的变量,我很抱歉这个noob问题,但是这是所有Ruby方法的标准吗?是否对方法中传入的参数进行更改?默认情况下,所有参数均为in/out?我不记得Java中发生过这种情况。不要抱歉,这不是一个noob问题,即使是,也不应该抱歉。选中此复选框,它将帮助您完成此主题。Major Major-您是否定义了任何读卡器/访问器?很可能您认为您有一个名为pos的局部变量,并且实际上正在调用一个名为pos的读取器方法。这在Java中也肯定会发生。例如,如果您修改了传入列表的内容,我仍然需要更改pos以在以后的方法中使用,我没有显示全部内容,只是显示相关部分,因此要使用pos.collect,我需要像在我的变通方法中那样声明一个新变量,对吗?问题更为严重的是,为什么@pos也被修改了。在这个答案上,ruby约定是任何带有!会有意想不到的副作用。最常见的是一个!将更改调用它的对象,但有时会产生其他副作用,如退出!它不调用任何退出处理程序就退出。当使用时!方法,请始终查阅文档并确保您了解其他情况。您需要按照@engineersmnky在注释中的建议执行dup,或将该集合分配给方法中的另一个变量,就像您对pos_programmed所做的那样,从那时起使用它。@MajorMajor也只是因为我是这里的引用。请记住,dup将复制外部容器,但如果您在内部操作项目,它们仍将保留其引用。e、 g.如果您更改了内部dup,则不会有帮助。对于一维数组,您可以使用.map&:dup,它将创建一个新数组,其中的对象是原始数组的副本,但任何其他对象都会进行深度复制。我会小心地说“您正在传递对该对象的引用”。这在Ruby中是不正确的。Ruby严格来说是按值传递的。是的,你是对的,它是按值传递的,但值是对对象的引用。这有点棘手,我这么看:“变量是对对象的引用”。你的最后一段对理解这里发生的事情非常有帮助,谢谢。