2009-11-08 17 views
5

Esta pregunta tiene dos partes.Extendiendo clases e instancias

En el libro de Ruby Programming Language, no es un ejemplo (sección 8.1.1) de extender un objeto de cadena y clase con un módulo.

Primera pregunta. ¿Por qué si extiendes una clase con un nuevo método y luego creas un objeto/instancia de esa clase, no puedes acceder a ese método?

irb(main):001:0> module Greeter; def ciao; "Ciao!"; end; end 
=> nil 
irb(main):002:0> String.extend(Greeter) 
=> String 
irb(main):003:0> String.ciao 
=> "Ciao!" 
irb(main):004:0> x = "foo bar" 
=> "foo bar" 
irb(main):005:0> x.ciao 
NoMethodError: undefined method `ciao' for "foo bar":String 
     from (irb):5 
     from :0 
irb(main):006:0> 

Segunda parte, Cuando trato de extender un objeto Fixnum, obtengo un error de método indefinido. ¿Alguien puede explicar por qué esto funciona para una cadena pero no un fixnum?

irb(main):045:0> module Greeter; def ciao; "Ciao!"; end; end 
=> nil 
irb(main):006:0> 3.extend(Greeter) 
TypeError: can't define singleton 
     from (irb):6:in `extend_object' 
     from (irb):6:in `extend' 
     from (irb):6 

Respuesta

9

Primera pregunta. ¿Por qué si amplía una clase con un nuevo método y y luego crea un objeto/instancia de esa clase , no puede acceder a ese método?

Dado que extendió la clase String, entonces #ciao es un método de clase y no un método de instancia.

String.send(:include, Greeter) 
x = "foo bar" 
x.ciao 
# => "Ciao!" 

la segunda parte, cuando intento de extender un objeto Fixnum , me sale un error indefinido método. ¿Alguien puede explicar por qué esto funciona para una cadena pero no un fixnum?

Aquí está el short answer.

"fixnums, símbolos, cierto, nula, y falsa se implementan como valores inmediatos. Con valores inmediatos, las variables tienen los objetos mismos, en lugar de referencias a ellos.

métodos

Singleton no puede se definirá para tales objetos. Dos Fixnums del mismo valor representan siempre la misma instancia de objeto , por lo que (por ejemplo) variables de instancia para el Fixnum con el valor "uno" se comparte entre todos los "unos" es el sistema. Esto hace imposible definir un conjunto unitario método para sólo uno de ellos."

¡Por supuesto, puede incluir/exten la clase Fixnum y cada instancia Fixnum expondrá a los métodos de la Mixin. Esto es exactamente lo que hace rieles/ActiveSupport con el fin de permitir escribir

3.days.ago 
1.hour.from_now 
+0

Su respuesta a la primera parte no explica (a mí) el por qué. En otros idiomas, cuando cambia la clase y crea un nuevo objeto de ese tipo de clase, obtiene el nuevo método. Estoy asumiendo que hay una conexión de clase a objetos que no es válida. ¿Puedes explicar por qué esa conexión no es válida aquí? – teleball

+0

Investigar el "incluir" que me diste ayudó. Entonces, parece que ahora que entiendo que existe una diferencia entre extender e incluir, y ahora sé qué buscar, hay una publicación aquí que explica esas diferencias: http://stackoverflow.com/questions/156362/what- is-the-difference-between-include-and-extend-in-ruby – teleball

2

obj.extend(module) añade todos los métodos en module a obj. Cuando llama como String.extend(Greeter) va a agregar los métodos de Greeter a th e instancia de Class que representa String.

La forma más fácil de agregar métodos de instancia adicionales a una clase existente es volver a abrir la clase.Los siguientes ejemplos hacen lo mismo:

class String 
    include Greeter 
end 

class String 
    def ciao 
    "Ciao!" 
    end 
end 

fixnums (así como Símbolos, verdadero, falso y nil) se manejan de una manera diferente a los casos normales. Dos Fixnums con el mismo valor siempre estarán representados por la misma instancia de objeto. Como resultado, Ruby no te permite extenderlos.

Se puede extender, por supuesto, una instancia de cualquier otra clase, por ejemplo .:

t = "Test" 
t.extend(Greeter) 
t.ciao 
=> "Ciao!" 
Cuestiones relacionadas