2009-11-30 3 views
4

J'ai rencontré une question étrange à propos de l'initialisation du message d'initialisation de BigDecimal.question à propos de la méthode d'initialisation surchargée

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 

Pourquoi je ne peux ignorer le message initialize de chaîne, mais pas de BigDecimal?

Répondre

2

Quand vous regardez dans les sources des classes Ruby, vous verrez que la classe String définit la méthode String#initialize, qui est appelée après String#new (hérité de Object) pour l'attribution d'une nouvelle instance. Vous n'appelez pas String#initialize (ou #super) dans votre nouvelle instance, vous avez donc "" lorsque vous inspectez l'objet nouvellement créé.

BigDecimal définit la méthode Bigdecimal#new, qui alloue son propre objet. La création d'objet se compose de deux parties: l'allocation d'espace pour un nouvel objet et son initialisation. Vous avez seulement défini l'initialisation d'un nouvel objet, donc vous restez avec l'allocation par défaut de l'espace pour l'objet. Si vous voulez le remplacer, vous devez définir #new dans votre nouvelle classe et appeler le #new avec les arguments appropriés.

espoir qui clarifie un peu ce qui se passe dans votre exemple.

+0

Je veux éclairer cela un peu plus. Puisque ruby ​​n'autorise pas la surcharge, elle n'autorise qu'une seule méthode 'initialize '. La dernière méthode définie sera la seule valide. En outre, il ne permettra qu'une seule méthode 'nouvelle '. Normalement, la nouvelle méthode (définie sur Object) appelle la méthode initialize, mais comme mentionné ici: le 'new 'BigDecimal est différent :) Vous devez donc redéfinir' self.new' bien que ce ne soit pas la méthode préférée. N'oubliez pas d'appeler 'super' avec les paramètres corrects, sinon vous n'aurez pas de BigDecimal. Normalement, vous n'auriez pas à définir de nouveau, – nathanvda

1

Il semble qu'il y ait une vérification de type qui se produit dans BigDecimal.new(), qui est perturbée avant que votre initialize substitué soit atteint. Voir le point 19 this list

Ce n'est pas souvent un problème (je me suis souvenu quelque chose, mais encore dû le chercher) mais il y a une méthode de classe new que, si je me souviens bien, crée en fait l'objet et appelle ensuite initialize.

Redéfinition new de la classe, ainsi:

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

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

donne la réponse espérée.

2

Oui, BigDecimal met en œuvre la nouvelle méthode de classe et si vous substituez que dans votre classe test2 alors vous pouvez écrire votre Test2 méthode initialize de quelque façon que vous voulez, par exemple

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

    def initialize(a) 
    puts a 
    end 
end 

Test2.new("a") 

La méthode de classe nouvelle est le constructeur d'objet qui définit l'état de l'objet et alloue de la mémoire une fois que l'objet est initialisé à l'aide de la méthode d'initialisation. Mais généralement nous n'implémentons pas la nouvelle méthode car c'est la méthode constructeur par défaut fournie par ruby ​​bien qu'elle puisse être surchargée en la redéfinissant dans votre classe s'il y a une forte raison pour cela et c'est ce que BigDecimal a terminé.