вопрос о переопределении метода инициализации - PullRequest
4 голосов
/ 30 ноября 2009

Я столкнулся со странным вопросом о переопределении сообщения инициализации 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?

Ответы [ 3 ]

2 голосов
/ 30 ноября 2009

Когда вы посмотрите на источники классов Ruby, вы увидите, что класс String определяет метод String#initialize, который вызывается после String#new (унаследовано от Object) для выделения нового экземпляра. Вы не вызываете String#initialize (или #super) в своем новом экземпляре, поэтому вы получаете "" при проверке вновь созданного объекта.

BigDecimal определяет метод Bigdecimal#new, который выделяет свой собственный объект. Создание объекта состоит из двух частей - выделения места для нового объекта и его инициализации. Вы только определили инициализацию нового объекта, так что вы останетесь с выделением пространства по умолчанию для объекта. Если вы хотите переопределить его, вы должны определить #new в вашем новом классе и вызвать BigDecimal s #new с соответствующими аргументами.

Надеюсь, это немного прояснит, что происходит в вашем примере.

2 голосов
/ 30 ноября 2009

Да, 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 ,

1 голос
/ 30 ноября 2009

Похоже, что в BigDecimal.new() происходит некоторая проверка типов, которая расстраивается до того, как будет достигнут ваш переопределенный initialize. См. Пункт 19 в этом списке

Это не часто проблема (я что-то вспомнил, но все еще должен был это найти), но есть метод класса new, который, если я правильно помню, фактически создает объект и затем вызывает initialize.

Переопределение new в классе, таким образом:

class Test2 < BigDecimal
  def Test2.new(a, b)
    puts a
    puts b
  end
end

Test2.new('42', 'banana')

дает ожидаемый ответ.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...