@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变量中的错误。
虽然我正在尝试做的更多的是一个黑客(似乎没有工作)。我想知道为什么变量值被洗掉了。我理解通过引用传递,所以我想知道值如何可以保存在那个变量中而不被洗掉。
试试这个:——
1.object_id
#=> 3
2.object_id
#=> 5
a = 1
#=> 1
a.object_id
#=> 3
b = 2
#=> 2
b.object_id
#=> 5
标识符a包含值对象1的object_id 3,标识符b包含值对象2的object_id 5。
现在这样做:——
a.object_id = 5
#=> error
a = b
#value(object_id) at b copies itself as value(object_id) at a. value object 2 has object_id 5
#=> 2
a.object_id
#=> 5
现在,a和b都包含相同的object_id 5,它指向值对象2。
因此,Ruby变量包含object_ids来引用值对象。
执行以下操作也会给出错误:——
c
#=> error
但是这样做不会产生错误:——
5.object_id
#=> 11
c = 5
#=> value object 5 provides return type for variable c and saves 5.object_id i.e. 11 at c
#=> 5
c.object_id
#=> 11
a = c.object_id
#=> object_id of c as a value object changes value at a
#=> 11
11.object_id
#=> 23
a.object_id == 11.object_id
#=> true
a
#=> Value at a
#=> 11
这里标识符a返回值对象11,其对象id为23,即object_id 23位于标识符a,现在我们看到一个使用method的例子。
def foo(arg)
p arg
p arg.object_id
end
#=> nil
11.object_id
#=> 23
x = 11
#=> 11
x.object_id
#=> 23
foo(x)
#=> 11
#=> 23
foo中的Arg被赋值为x。
它清楚地表明参数是由值11传递的,值11本身是一个对象,对象id为23。
现在再看这个:——
def foo(arg)
p arg
p arg.object_id
arg = 12
p arg
p arg.object_id
end
#=> nil
11.object_id
#=> 23
x = 11
#=> 11
x.object_id
#=> 23
foo(x)
#=> 11
#=> 23
#=> 12
#=> 25
x
#=> 11
x.object_id
#=> 23
在这里,标识符arg首先包含object_id 23来引用11,在对值对象12进行内部赋值后,它包含object_id 25。但它不会改变在调用方法中使用的标识符x引用的值。
因此,Ruby是按值传递的,Ruby变量不包含值,但包含对值对象的引用。
其他的答案都是正确的,但是一个朋友让我向他解释这一点,归根结底就是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的“按值传递引用”如何工作的理论,有很多很棒的答案。但以身作则,我能更好地学习和理解一切。希望这对你们有帮助。
def foo(bar)
puts "bar (#{bar}) entering foo with object_id #{bar.object_id}"
bar = "reference"
puts "bar (#{bar}) leaving foo with object_id #{bar.object_id}"
end
bar = "value"
puts "bar (#{bar}) before foo with object_id #{bar.object_id}"
foo(bar)
puts "bar (#{bar}) after foo with object_id #{bar.object_id}"
# Output
bar (value) before foo with object_id 60
bar (value) entering foo with object_id 60
bar (reference) leaving foo with object_id 80 # <-----
bar (value) after foo with object_id 60 # <-----
正如你所看到的,当我们输入这个方法时,我们的工具条仍然指向字符串“value”。但是之后我们给bar分配了一个字符串对象“reference”,它有一个新的object_id。在这种情况下,foo内部的bar具有不同的作用域,无论我们在方法中传递什么,当我们重新分配它并将其指向内存中包含String "reference"的新位置时,bar都不再访问它。
现在考虑同样的方法。唯一的区别是在方法中使用do
def foo(bar)
puts "bar (#{bar}) entering foo with object_id #{bar.object_id}"
bar.replace "reference"
puts "bar (#{bar}) leaving foo with object_id #{bar.object_id}"
end
bar = "value"
puts "bar (#{bar}) before foo with object_id #{bar.object_id}"
foo(bar)
puts "bar (#{bar}) after foo with object_id #{bar.object_id}"
# Output
bar (value) before foo with object_id 60
bar (value) entering foo with object_id 60
bar (reference) leaving foo with object_id 60 # <-----
bar (reference) after foo with object_id 60 # <-----
注意到区别了吗?我们在这里所做的是:我们修改了String对象的内容,变量所指向的对象。bar的范围在方法内部仍然是不同的。
所以要注意如何处理传递给方法的变量。如果修改传入的变量-in-place (gsub!, replace, etc),然后在方法的名称中以砰的一声表示so,比如“def foo!”
注:
重要的是要记住,foo的“bar”的内部和外部是“不同的”“bar”。它们的范围不同。在该方法中,您可以将“bar”重命名为“club”,结果将是相同的。
我经常看到变量在方法内部和外部被重用,虽然这很好,但它降低了代码的可读性,是一种代码气味。我强烈建议不要做我在上面例子中所做的:),而是这样做
def foo(fiz)
puts "fiz (#{fiz}) entering foo with object_id #{fiz.object_id}"
fiz = "reference"
puts "fiz (#{fiz}) leaving foo with object_id #{fiz.object_id}"
end
bar = "value"
puts "bar (#{bar}) before foo with object_id #{bar.object_id}"
foo(bar)
puts "bar (#{bar}) after foo with object_id #{bar.object_id}"
# Output
bar (value) before foo with object_id 60
fiz (value) entering foo with object_id 60
fiz (reference) leaving foo with object_id 80
bar (value) after foo with object_id 60