为什么是程序的输出:
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: {5}>
而不是
#<Set: {1,2,5}>
方法add
被重新定义为使用参数5
运行。
答案 0 :(得分:3)
查看Set::new
的来源:
# File set.rb, line 80
def initialize(enum = nil, &block) # :yields: o
@hash ||= Hash.new
enum.nil? and return
if block
do_with_enum(enum) { |o| add(block[o]) }
else
# you did not supply any block, when you called `new`
# thus else part will be executed here
merge(enum)
end
end
似乎Set.new
在内部调用方法#add
。在OP的示例中,block
为nil
,因此调用了#merge
:
# 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
因此add
(enum
)的每个元素都会调用[1,2]
。在这里,您覆盖了原始的#add
方法,并且在该方法中,您使用参数#add
调用旧的5
方法。
Set实现了一组无序值,没有重复。因此,即使您添加5
两次,您也只能获得一个5
。这是您没有获得#<Set: {1,2}>
,而是#<Set: {5}>
的原因。如下所示,当您致电Set.new
时,对象#<Set: {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}>
当您致电s.add(3)
时,系统会调用您重写的add
方法,并再次将5
传递给旧的add
方法。正如我之前所说,Set
不包含重复值,因此该对象仍将与之前的#<Set: {5}>
相同。
答案 1 :(得分:0)
当您使用给定成员实例化新集时,将使用add
方法添加成员。这可以通过在创建它之后调查该集来显示:
Set.new([1,2])
# => #<Set: {5}>
因此,当你执行s.add(3)
时,你基本上再次添加5
,它已经被添加了两次,因此该方法实际上并没有改变集合。