重新定义Ruby方法的怪异行为

重新定义Ruby方法的怪异行为,ruby,Ruby,为什么程序的输出是: require 'set' class Set alias :old_add :add def add(arg) arg = 5 old_add arg end end s = Set.new ([1,2]) s.add(3) puts s.inspect 存在 # 相对于 #<Set: {1,2,5}> # 方法add被重新定义为与参数5一起运行,查看以下内容的源: 似乎Set.new在内部调用方法#add。在OP的示

为什么程序的输出是:

require 'set'

class Set
  alias :old_add :add
  def add(arg)
    arg = 5
    old_add arg
  end
end

s = Set.new ([1,2])
s.add(3)

puts s.inspect
存在

#
相对于

#<Set: {1,2,5}>
#
方法
add
被重新定义为与参数
5

一起运行,查看以下内容的源:

似乎
Set.new
在内部调用方法
#add
。在OP的示例中,
nil
,因此称为:

# File set.rb, line 351
def merge(enum)
  if enum.instance_of?(self.class)
    @hash.update(enum.instance_variable_get(:@hash))
  else
    # in your case this else part will be executed.
    do_with_enum(enum) { |o| add(o) }
  end

  self
end
因此,为
enum
的每个元素调用
add
[1,2]
)。这里,您覆盖了原始的
#add
方法,在该方法中,您使用参数
5
调用旧的
#add
方法

Set实现了一个无重复项的无序值的集合。因此,即使您添加了两次
5
,也只能得到一个
5
。这就是为什么您没有得到
,而是
。如下所示,当您调用
Set.new
时,将创建对象
#
,正如我上面解释的那样:

require 'set'

class Set
  alias :old_add :add
  def add(arg)
    arg = 5
    old_add arg
  end
end

s = Set.new ([1,2])
s # => #<Set: {5}>
require'set'
类集
别名:old_add:add
def添加(arg)
arg=5
old_add arg
结束
结束
s=Set.new([1,2])
s#=>#

当调用
s.add(3)
时,调用了重写的
add
方法,它再次将
5
传递给旧的
add
方法。如前所述,
Set
不包含重复的值,因此对象仍将与先前的
#

相同。当您使用给定成员实例化一个新集合时,将使用
add
方法添加成员。这可以通过在创建集合后调查集合来显示:

Set.new([1,2])
# => #<Set: {5}>
Set.new([1,2])
# => #
因此,当您执行
s.add(3)
时,基本上是再次添加
5
,它已经添加到集合中两次,因此该方法实际上不会更改集合

require 'set'

class Set
  alias :old_add :add
  def add(arg)
    arg = 5
    old_add arg
  end
end

s = Set.new ([1,2])
s # => #<Set: {5}>
Set.new([1,2])
# => #<Set: {5}>