En Ruby, ¿cuál es la relación entre ‘nuevo’ e ‘inicializar’? ¿Cómo devolver nil durante la inicialización?

Lo que quiero es:

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

Esto no funciona:

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

Sé que en C / C ++ / Java / C #, no podemos devolver un valor en un constructor.

Pero me pregunto si es posible en Ruby.

En Ruby, ¿cuál es la relación entre ‘ new ‘ e ‘ initialize ‘?

new normalmente, las llamadas se initialize . La implementación predeterminada de new es algo así como:

 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 

Pero puede, por supuesto, anularlo para hacer lo que quiera.

¿Cómo devolver nil durante la inicialización?

Lo que quiero es:

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

Esto no funciona:

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

Sé que en C / C ++ / Java / C #, no podemos devolver un valor en un constructor.

Pero me pregunto si es posible en Ruby.

No existe un constructor en Ruby. Los constructores son innecesarios en un lenguaje bien diseñado. En Ruby, solo hay métodos y, por supuesto, los métodos pueden devolver valores.

El problema que está viendo es simplemente que desea cambiar el valor de retorno de un método, pero está anulando un método diferente. Por supuesto que eso no funciona. Si desea cambiar el valor de retorno de la bar de métodos, debe anular la bar , no algún otro método.

Si desea cambiar el comportamiento de Foo::new , entonces debe cambiar Foo::new :

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

Tenga en cuenta, sin embargo, que esta es una idea realmente mala , ya que viola el contrato de new , que es devolver una instancia de la clase totalmente inicializada y en pleno funcionamiento.

Hay diferencias importantes entre los dos métodos.

new es un método de clase , que generalmente crea una instancia de la clase (esto trata de cosas difíciles como asignar memoria que Ruby te protege para que no tengas que ensuciarte demasiado).

Luego, initialize , un método de instancia , le dice al objeto que configure su estado interno según los parámetros solicitados.

Cualquiera de estos puede ser anulado dependiendo de lo que desee. Por ejemplo, Foo.new podría crear y devolver una instancia de FooSubclass si necesita ser lo suficientemente inteligente como para hacerlo.

Sin embargo, a menudo es mejor delegar casos de uso como estos en otros métodos de clase que son más explícitos sobre lo que hacen, por ejemplo Foo.relating_to(bar) . Romper las expectativas de otras personas sobre lo que deben hacer los métodos new debería confundir a las personas más de lo que las ayudará a largo plazo.

Como ejemplo, observe la implementación de Singleton , un módulo que permite que solo exista una instancia de una clase en particular. Hace que el new método sea privado y expone un método de instance que devuelve la instancia existente del objeto o llama a new si aún no se ha creado.

Puedes algo como esto:

 class Foo def self.init(val) new(val) unless val == 0 end def initialize(val) #... end end 

Ejemplo de uso:

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

Queriendo hacer

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

haría un código inconsistente.

Si tuvieras

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

¿Qué le gustaría recuperar si lo hiciera con Foo.new(1) ? ¿Le gustaría 42 (el valor de retorno para Foo#initialize ), o un objeto foo ? Si quieres un objeto foo para Foo.new(1) , entonces ¿por qué esperas que return nil haga que Foo.new(0) devuelva nil?

Se resuelve simplemente creando una variable de objeto como esta:

 class Foo def initialize(val) @val = val return nil if @val == 0 end end obj = Foo.new(0) Output:- =># 

La salida varía en diferentes computadoras.