@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变量中的错误。

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


当前回答

需要注意的是,您甚至不需要使用“replace”方法来更改原始值。如果你为一个哈希值分配了其中一个哈希值,你就是在改变原始值。

def my_foo(a_hash)
  a_hash["test"]="reference"
end;

hash = {"test"=>"value"}
my_foo(hash)
puts "Ruby is pass-by-#{hash["test"]}"

其他回答

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

已经有了一些很好的答案,但我想在这里发布关于这个主题的一对权威的定义,但也希望有人能解释一下权威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.

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

需要注意的是,您甚至不需要使用“replace”方法来更改原始值。如果你为一个哈希值分配了其中一个哈希值,你就是在改变原始值。

def my_foo(a_hash)
  a_hash["test"]="reference"
end;

hash = {"test"=>"value"}
my_foo(hash)
puts "Ruby is pass-by-#{hash["test"]}"

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

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

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

def foo(bar)
  bar = 'reference'
end

baz = 'value'

foo(baz)

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

Ruby使用“对象引用传递”

(使用Python术语。)

说Ruby使用“按值传递”或“按引用传递”并不是真正的描述性足够有帮助。我想现在大多数人都知道,这个术语(“值”vs“引用”)来自c++。

在c++中,“传递值”意味着函数获得变量的副本,对副本的任何更改都不会改变原始变量。对象也是如此。如果你通过值传递一个对象变量,那么整个对象(包括它的所有成员)都会被复制,对成员的任何更改都不会改变原始对象上的那些成员。(如果你通过值传递一个指针,这是不同的,但Ruby没有指针,AFAIK。)

class A {
  public:
    int x;
};

void inc(A arg) {
  arg.x++;
  printf("in inc: %d\n", arg.x); // => 6
}

void inc(A* arg) {
  arg->x++;
  printf("in inc: %d\n", arg->x); // => 1
}

int main() {
  A a;
  a.x = 5;
  inc(a);
  printf("in main: %d\n", a.x); // => 5

  A* b = new A;
  b->x = 0;
  inc(b);
  printf("in main: %d\n", b->x); // => 1

  return 0;
}

输出:

in inc: 6
in main: 5
in inc: 1
in main: 1

在c++中,“引用传递”意味着函数可以访问原始变量。它可以分配一个全新的字面值整数,然后原始变量也会有这个值。

void replace(A &arg) {
  A newA;
  newA.x = 10;
  arg = newA;
  printf("in replace: %d\n", arg.x);
}

int main() {
  A a;
  a.x = 5;
  replace(a);
  printf("in main: %d\n", a.x);

  return 0;
}

输出:

in replace: 10
in main: 10

如果参数不是一个对象,Ruby使用按值传递(在c++的意义上)。但是在Ruby中,所有的东西都是一个对象,所以在Ruby中没有c++意义上的值传递。

在Ruby中,“通过对象引用传递”(使用Python的术语)被使用:

在函数内部,对象的任何成员都可以有新的值赋给他们,这些变化将在函数返回.*后持续存在 在函数内部,将一个全新的对象赋值给变量会导致变量停止引用旧对象。但是在函数返回后,原始变量仍然会引用旧对象。

因此Ruby不使用c++意义上的“引用传递”。如果存在,那么将一个新对象分配给函数内的变量将导致在函数返回后忘记旧对象。

class A
  attr_accessor :x
end

def inc(arg)
  arg.x += 1
  puts arg.x
end

def replace(arg)
  arg = A.new
  arg.x = 3
  puts arg.x
end

a = A.new
a.x = 1
puts a.x  # 1

inc a     # 2
puts a.x  # 2

replace a # 3
puts a.x  # 2

puts ''

def inc_var(arg)
  arg += 1
  puts arg
end

b = 1     # Even integers are objects in Ruby
puts b    # 1
inc_var b # 2
puts b    # 1

输出:

1
2
2
3
2

1
2
1

*这就是为什么在Ruby中,如果你想在函数中修改一个对象,但在函数返回时忘记这些更改,那么你必须在对副本进行临时更改之前显式地创建一个对象的副本。