7
>> 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 中的?

4

2 回答 2

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 中的一些对象是直接的。它们是按值传递的,这个值只能有一个,因此不能被欺骗。这些是任何(小)整数、truefalse、 符号和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 选择不在dup立即数上定义。

你的问题比看起来更复杂。有一些关于 ruby​​-core 的讨论,关于如何使这更容易。此外,其他类型的数值对象(浮点数、大数、有理数和复数)也不能被欺骗,尽管它们也不是立即数。

请注意,ActiveSupport(rails 的一部分)为duplicable?所有对象提供方法

于 2009-12-26T20:12:46.517 回答
3

您定义的函数的问题dup()在于它不返回对象的副本,而是返回对象本身。这不是duplicate程序应该做的事情。

我不了解 Ruby,但我能想到的dup未为数字定义的一个可能原因是数字是一种基本类型,因此,可以执行以下操作:

>> a = 5
>> b = a

会自动将值分配给5变量b,而不是在内存中创建ba指向相同的值。

于 2009-12-26T19:35:44.780 回答