我遇到了一个关于覆盖BigDecimal初始化消息的奇怪问题。
class Test1 < String
def initialize(a, b)
puts a
puts b
end
end
require 'bigdecimal'
class Test2 < BigDecimal
def initialize(a, b)
puts a
puts b
end
end
>> Test1.new('a', 'b')
a
b
>> Test2.new('a', 'b')
TypeError: wrong argument type String (expected Fixnum)
from (irb):17:in `new'
from (irb):17
为什么我可以覆盖String的初始化消息,但不能覆盖BigDecimal?
答案 0 :(得分:2)
当您查看Ruby类的来源时,您会看到String
类定义方法String#initialize
,该方法在String#new
之后调用(继承自Object
)用于分配新实例。您不要在新实例中调用String#initialize
(或#super
),以便在检查新创建的对象时获得""
。
BigDecimal
定义方法Bigdecimal#new
,它分配自己的对象。对象创建由两部分组成 - 为新对象分配空间并初始化它。您只定义了初始化新对象,因此您可以使用默认的对象分配空间。如果您要覆盖它,则应在新课程中定义#new
,并使用适当的参数调用BigDecimal
的{{1}}。
希望能澄清你的例子中发生的事情。
答案 1 :(得分:2)
是的,BigDecimal实现了新的类方法,如果你在test2类中覆盖它,那么你可以用任何你想要的方式编写Test2初始化方法,例如。
class Test2 < BigDecimal
def self.new(a)
puts a
end
def initialize(a)
puts a
end
end
Test2.new("a")
类方法new是对象构造函数,它使用initialize方法设置对象状态并在初始化对象后分配内存。
但是通常我们不实现新方法,因为它是ruby提供的默认构造方法,尽管如果有充分的理由可以通过在类中重新定义它来覆盖它,那就是BigDecimal所做的。
答案 2 :(得分:1)
看起来BigDecimal.new()
中发生了一些类型检查,在达到被覆盖的initialize
之前就会感到沮丧。见this list
这通常不是一个问题(我记得一些东西,但仍然要查找它)但是有一个new
类方法,如果我没记错的话,实际创建了对象,然后调用initialize
。
覆盖课堂上的new
,因此:
class Test2 < BigDecimal
def Test2.new(a, b)
puts a
puts b
end
end
Test2.new('42', 'banana')
给出了希望的答案。