numeros - En Ruby, ¿cuál es la relación entre ''nuevo'' e ''inicializar''? ¿Cómo devolver nil durante la inicialización?
numeros en ruby (5)
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)
=> #<Foo:0x00000002970a98>
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:-
=>#<Foo:0x1243b8 @val=0>
La salida varía en diferentes computadoras.