57 votes

En Ruby, quelle est la relation entre "nouveau" et "initialiser"? Comment retourner nil en initialisant?

Ce que je veux c'est:

 obj = Foo.new(0)  # => nil or false
 

Cela ne marche pas:

 class Foo
  def initialize(val)
    return nil if val == 0
  end
end
 

Je sais qu'en C / C ++ / Java / C #, nous ne pouvons pas renvoyer de valeur dans un constructeur.

Mais je me demande si c'est possible en Ruby.

86voto

Jörg W Mittag Points 153275

En Ruby, quelle est la relation entre"new"et"initialize'?

new appelle généralement initialize. L'implémentation par défaut de new est quelque chose comme:

class Class
  def new(*args, &block)
    obj = allocate

    obj.initialize(*args, &block)
    # actually, this is obj.send(:initialize, …) because initialize is private

    obj
  end
end

Mais vous pouvez, bien sûr, de la remplacer pour faire ce que vous voulez.

Comment retourner nil lors de l'initialisation?

Ce que je veux, c'est:

obj = Foo.new(0)  # => nil or false

Cela ne fonctionne pas:

class Foo
  def initialize(val)
    return nil if val == 0
  end
end

Je sais en C/C++/Java/C#, nous ne pouvons pas retourner une valeur dans un constructeur.

Mais je me demande s'il est possible en Ruby.

Il n'y a pas une telle chose comme un constructeur en Ruby. Les constructeurs sont inutiles dans un système bien conçu de la langue. En Ruby, il y a seulement des méthodes et des cours de méthodes peut renvoyer des valeurs.

Le problème que vous rencontrez est tout simplement que vous souhaitez modifier la valeur de retour d'une méthode, mais vous écrasez une méthode différente. Bien sûr, cela ne fonctionne pas. Si vous souhaitez modifier la valeur de retour de la méthode bar, vous devez remplacer bar, et non pas une autre méthode.

Si vous souhaitez modifier le comportement de l' Foo::new, alors vous devez changer Foo::new:

class Foo
  def self.new(val)
    return nil if val.zero?
    super
  end
end

Notez, cependant, que c'est une très mauvaise idée, car elle viole le contrat d' new, qui est de retourner complètement initialisé, entièrement le fonctionnement de l'instance de la classe.

49voto

Gareth Points 42402

Il existe d'importantes différences entre les deux méthodes.

new est une classe de la méthode, ce qui crée généralement une instance de la classe (il s'agit des choses difficiles comme l'allocation de mémoire que Ruby vous protège de sorte que vous n'avez pas trop sale).

Ensuite, initialize, un exemple de la méthode, indique à l'objet de définir son état interne selon les paramètres demandés.

Chacun de ces programmes peut être remplacée en fonction de ce que vous voulez. Par exemple, Foo.new pourrait en fait créer et retourner une instance de FooSubclass si elle doit être assez intelligent pour le faire.

Cependant, il est souvent préférable de déléguer l'utilisation de tels cas, d'autres méthodes de la classe qui sont plus explicites sur ce qu'ils font, par exemple, Foo.relating_to(bar). Casser les autres peuples attentes sur les méthodes comme new devrait ne va embrouiller les gens plus que ce qu'il va les aider dans le long terme.

Comme un exemple, regardez la mise en œuvre de l' Singleton, un module qui permet à une seule instance d'une classe particulière d'exister. Il rend l' new méthode privée, et expose une instance méthode qui renvoie l'instance existante de l'objet, ou des appels new si elle n'a pas encore été créé.

8voto

Flexoid Points 2730

Vous pouvez quelque chose comme ça:

 class Foo

  def self.init(val)
    new(val) unless val == 0
  end

  def initialize(val)
    #...
  end
end
 

Exemple d'utilisation:

 obj = Foo.init(0)
 => nil
obj = Foo.init(5)
 => #<Foo:0x00000002970a98>
 

5voto

Andrew Grimm Points 22996

Vouloir faire

 class Foo
  def initialize(val)
    return nil if val == 0
  end
end
 

conduirait à un code incohérent.

Si tu avais

 class Foo
  def initialize(val)
    return nil if val == 0
    @val = val
    @bar = 42
  end
end
 

que voudriez-vous récupérer si vous faisiez Foo.new(1) ? Voulez-vous 42 (la valeur de retour pour Foo#initialize ) ou un objet foo ? Si vous souhaitez un objet foo pour Foo.new(1) , alors pourquoi vous attendriez-vous à ce que return nil rende Foo.new(0) nul?

-2voto

lucifer Points 1

Il est résolu simplement en créant une variable d'objet comme celle-ci

 class Foo
   def initialize(val)
       @val = val
       return nil if @val == 0
   end
end
obj = Foo.new(0)

Output:-
=>#<Foo:0x1243b8 @val=0>
 

La sortie varie selon les ordinateurs.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X