>> a = 5
=> 5
>> b = "hello, world!"
=> "hello, world!"
>> b.dup
=> "hello, world!"
>> a.dup
TypeError: can't dup Fixnum
from (irb):4:in `dup'
from (irb):4
我知道Ruby会在每次为新变量分配整数时制作副本,但为什么Numeric#dup
会引发错误?
这不会破坏抽象,因为所有对象都应该正确响应.dup
吗?
据我所知,重写dup
方法将解决问题:
>> class Numeric
>> def dup()
>> self
>> end
>> end
这有没有我看不到的缺点?为什么不将它内置到Ruby中?
答案 0 :(得分:15)
Ruby中的大多数对象都是通过引用传递的,可以复制。例如:
s = "Hello"
t = s # s & t reference to the same string
t.upcase! # modifying either one will affect the other
s # ==> "HELLO"
但Ruby中的一些对象是即时的。它们按值传递,只能有一个这个值,因此不能被欺骗。这些是任何(小)整数,true
,false
,符号和nil
。许多浮点数在64位系统上的Ruby 2.0中也是最重要的。
在这个(荒谬的)例子中,任何“42”都将保存相同的实例变量。
class Fixnum
attr_accessor :name
alias_method :original_to_s, :to_s
def to_s
name || original_to_s
end
end
42.name = "The Answer"
puts *41..43 # => 41, The Answer, 43
由于您通常希望something.dup.name = "new name"
不影响使用dup
获得的副本之外的任何其他对象,因此Ruby选择不在immediates上定义dup
。
你的问题比它看起来更复杂。 ruby-core上有some discussion关于如何使这更容易。此外,其他类型的数字对象(浮动,bignums,有理数和复数)也不能被欺骗,尽管它们也不是中立的。
请注意,ActiveSupport(rails的一部分)在所有对象上提供方法duplicable?
答案 1 :(得分:3)
您定义的dup()
函数的问题是它不返回对象的副本,而是返回对象本身。这不是duplicate
程序应该做的事情。
我不知道Ruby,但我可以想到dup
没有为数字定义的一个原因是数字是一个基本类型,因此做了类似的事情:
>> a = 5
>> b = a
会自动将值5
分配给变量b
,而不是让b
和a
指向内存中的相同值。