@user.update_languages(params[:language][:language1], 
                       params[:language][:language2], 
                       params[:language][:language3])
lang_errors = @user.errors
logger.debug "--------------------LANG_ERRORS----------101-------------" 
                + lang_errors.full_messages.inspect

if params[:user]
  @user.state = params[:user][:state]
  success = success & @user.save
end
logger.debug "--------------------LANG_ERRORS-------------102----------" 
                + lang_errors.full_messages.inspect

if lang_errors.full_messages.empty?

@user对象将错误添加到update_languages方法中的lang_errors变量中。 当我在@user对象上执行保存时,我丢失了最初存储在lang_errors变量中的错误。

虽然我正在尝试做的更多的是一个黑客(似乎没有工作)。我想知道为什么变量值被洗掉了。我理解通过引用传递,所以我想知道值如何可以保存在那个变量中而不被洗掉。


当前回答

其他的答案都是正确的,但是一个朋友让我向他解释这一点,归根结底就是Ruby是如何处理变量的,所以我想分享一些我为他写的简单的图片/解释(很抱歉篇幅太长,可能有些过于简化了):


Q1:当你将一个新变量str赋值为'foo'时会发生什么?

str = 'foo'
str.object_id # => 2000

答:一个名为str的标签被创建,指向对象'foo',对于这个Ruby解释器的状态来说,它恰好位于内存位置2000。


Q2:当你使用=将现有变量str赋值给一个新对象时会发生什么?

str = 'bar'.tap{|b| puts "bar: #{b.object_id}"} # bar: 2002
str.object_id # => 2002

A:标签str现在指向一个不同的对象。


Q3:当你分配一个新的变量= str会发生什么?

str2 = str
str2.object_id # => 2002

答:创建一个名为str2的新标签,指向与str相同的对象。


Q4:如果被str和str2引用的对象被改变了会发生什么?

str2.replace 'baz'
str2 # => 'baz'
str  # => 'baz'
str.object_id # => 2002
str2.object_id # => 2002

答:两个标签仍然指向同一个对象,但是对象本身已经发生了变化(它的内容已经改变为其他东西)。


这和最初的问题有什么关系?

这与第三季度和第四季度的情况基本相同;该方法获得传入给它的变量/ label (str2)的私有副本(str)。它不能改变标签str指向的对象,但它可以改变它们都引用的对象的内容,以包含else:

str = 'foo'

def mutate(str2)
  puts "str2: #{str2.object_id}"
  str2.replace 'bar'
  str2 = 'baz'
  puts "str2: #{str2.object_id}"
end

str.object_id # => 2004
mutate(str) # str2: 2004, str2: 2006
str # => "bar"
str.object_id # => 2004

其他回答

Ruby是严格意义上的值传递,但是值是引用。

这可以称为“pass-reference-by-value”。这篇文章有我读过的最好的解释:http://robertheaton.com/2014/07/22/is-ruby-pass-by-reference-or-pass-by-value/

按值传递引用可以简单地解释如下:

函数接收(并将访问)调用者在内存中使用的同一对象的引用。但是,它不接收调用方存储该对象的盒子;与pass-value-by-value一样,函数提供自己的方框,并为自己创建一个新变量。

结果行为实际上是引用传递和值传递的经典定义的组合。

其他的答案都是正确的,但是一个朋友让我向他解释这一点,归根结底就是Ruby是如何处理变量的,所以我想分享一些我为他写的简单的图片/解释(很抱歉篇幅太长,可能有些过于简化了):


Q1:当你将一个新变量str赋值为'foo'时会发生什么?

str = 'foo'
str.object_id # => 2000

答:一个名为str的标签被创建,指向对象'foo',对于这个Ruby解释器的状态来说,它恰好位于内存位置2000。


Q2:当你使用=将现有变量str赋值给一个新对象时会发生什么?

str = 'bar'.tap{|b| puts "bar: #{b.object_id}"} # bar: 2002
str.object_id # => 2002

A:标签str现在指向一个不同的对象。


Q3:当你分配一个新的变量= str会发生什么?

str2 = str
str2.object_id # => 2002

答:创建一个名为str2的新标签,指向与str相同的对象。


Q4:如果被str和str2引用的对象被改变了会发生什么?

str2.replace 'baz'
str2 # => 'baz'
str  # => 'baz'
str.object_id # => 2002
str2.object_id # => 2002

答:两个标签仍然指向同一个对象,但是对象本身已经发生了变化(它的内容已经改变为其他东西)。


这和最初的问题有什么关系?

这与第三季度和第四季度的情况基本相同;该方法获得传入给它的变量/ label (str2)的私有副本(str)。它不能改变标签str指向的对象,但它可以改变它们都引用的对象的内容,以包含else:

str = 'foo'

def mutate(str2)
  puts "str2: #{str2.object_id}"
  str2.replace 'bar'
  str2 = 'baz'
  puts "str2: #{str2.object_id}"
end

str.object_id # => 2004
mutate(str) # str2: 2004, str2: 2006
str # => "bar"
str.object_id # => 2004

已经有了一些很好的答案,但我想在这里发布关于这个主题的一对权威的定义,但也希望有人能解释一下权威Matz (Ruby的创造者)和David Flanagan在他们的O'Reilly著作《Ruby编程语言》中所说的意思。

[from 3.8.1: Object References] When you pass an object to a method in Ruby, it is an object reference that is passed to the method. It is not the object itself, and it is not a reference to the reference to the object. Another way to say this is that method arguments are passed by value rather than by reference, but that the values passed are object references. Because object references are passed to methods, methods can use those references to modify the underlying object. These modifications are then visible when the method returns.

直到最后一段,尤其是最后一句,我才明白这一切。往好了说是误导,往坏了说是混淆。对值传递引用的修改如何以任何方式改变底层对象?

Ruby是通过引用传递还是通过值传递?

Ruby是值传递。总是这样。没有例外。没有如果。少啰嗦

下面是一个简单的程序,说明了这一事实:

def foo(bar)
  bar = 'reference'
end

baz = 'value'

foo(baz)

puts "Ruby is pass-by-#{baz}"
# Ruby is pass-by-value

参数是原始引用的副本。因此,您可以更改值,但不能更改原始引用。