2012-04-30 9 views
42

Lo que quiero es:En Ruby, ¿cuál es la relación entre 'nuevo' e 'inicializar'? ¿Cómo devolver nil durante la inicialización?

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

esto no funciona:

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

que conozco en C/C++/Java/C#, nosotros no podemos devolver un valor en un constructor.

Pero me pregunto si es posible en Ruby.

+12

Si se trata de un control de cordura, una cosa más amigable sería plantear una excepción explicando * por qué * no continúa la inicialización. Devolver nil solo va a crear una confusión (seria). Nadie esperaría que un objeto recién instanciado sea nulo;) – d11wtq

+0

No hay constructores en 'C'. – YoTengoUnLCD

+3

La notable excepción a la declaración de @ d11wtq sería 'NilClass.new()'. –

Respuesta

5

Usted puede 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) 
=> #<Foo:0x00000002970a98> 
+0

En su ejemplo, ¿esta llamada también es nueva? – holaSenor

+0

Si te refieres al ejemplo cuando llamamos 'init' a 0, entonces no, el' nuevo' no será invocado. – Flexoid

42

Existen diferencias importantes entre los dos métodos.

new es un método de clase , que generalmente crea una instancia de la clase (esto se ocupa de las cosas difíciles como la asignación de memoria que Ruby le protege de modo que no tiene que ser demasiado sucia).

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

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

Sin embargo, a menudo es mejor delegar casos de uso como estos a 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 cómo los métodos como new deberían hacer confundirá a las personas más de lo que les ayudará a largo plazo.

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

71

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

new normalmente llamadas 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 se puede, por supuesto, anularlo para hacer cualquier cosa que desee.

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 

que conozco en C/C++/Java/C#, nosotros no podemos devolver un valor en un constructor.

Pero me pregunto si es posible en Ruby.

No hay tal cosa como 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 no funciona. Si desea cambiar el valor de retorno del método bar, debe anular bar, no algún otro método.

Si desea cambiar el comportamiento de Foo::new, entonces debería cambiar Foo::new:

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

Nótese, sin embargo, que este es un muy mala idea, ya que viola el contrato de new, que es devolver una instancia completamente inicializada y completamente funcional de la clase.

+0

¿Es 'self.new' correcto? ¿No debería ser 'Foo.new'? – Kashyap

+2

'self' * es *' Foo' allí. Prueba 'clase Foo; p autodeterminación # => Foo' –

4

Querer hacer

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

haría para el código inconsistente.

Si tuviera

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

¿qué le gustaría volver si lo hizo Foo.new(1)? ¿Desea 42 (el valor de retorno para Foo#initialize) o un objeto foo? Si desea un objeto foo para Foo.new(1), entonces ¿por qué esperaría que return nil haga Foo.new(0) return nil?

-1

Se resuelve simplemente creando una variable de objeto como esto:

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

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

La salida varía en diferentes ordenadores.

2

Las clases en Ruby son objetos de primera clase; cada una es una instancia de clase Class. Cuando se define una nueva clase (normalmente utilizando el nombre de la clase ... fin), se crea un objeto de tipo Clase y se le asigna una constante (Nombre, en este caso). Cuando se llama a Name.new para crear un nuevo objeto, el nuevo método de clase en Class se ejecuta de forma predeterminada, que a su vez invoca asignar para asignar memoria para el objeto, antes de llamar finalmente al método de inicialización del nuevo objeto. Las fases de construcción e inicialización de un objeto están separadas y ambas pueden ser anuladas. La construcción se realiza mediante el nuevo método de clase, la inicialización se realiza mediante el método de instancia de inicialización. ¡Inicializar no es un constructor!

Cuestiones relacionadas