2009-07-08 12 views
7

Entiendo que se supone que no debes subclase Fixnum, Float o Integer directamente, ya que no tienen un #nuevo método. Sin embargo, el uso de DelegateClass parece funcionar, pero ¿es la mejor manera? ¿Alguien sabe cuál es la razón detrás de estas clases que no tienen #new?Subcategoría Fixnum en ruby ​​

necesito una clase que se comporta como un Fixnum, pero tiene algunos métodos adicionales, y me gustaría ser capaz de hacer referencia a su valor a través self desde dentro de la clase, por ejemplo:

class Foo < Fixnum 
    def initialize value 
    super value 
    end 

    def increment 
    self + 1 
    end 
end 

Foo.new(5).increment + 4 # => 10 
+0

Cuéntanos qué estás realmente tratando de hacer (el objetivo final), e intentaremos decirte la mejor manera de hacerlo. No creo que la subclasificación sea apropiada aquí. –

+0

actualizó la pregunta. – cloudhead

Respuesta

17

Puede muy fácilmente configurar una implementación rápida de reenvío de sí mismo:

class MyNum 
    def initialize(number) 
    @number = number 
    end 

    def method_missing(name, *args, &blk) 
    ret = @number.send(name, *args, &blk) 
    ret.is_a?(Numeric) ? MyNum.new(ret) : ret 
    end 
end 

continuación, puede añadir cualquier método que desee en myNum, pero necesitará para operar en @number en esos métodos, en lugar de poder llamar súper directamente.

+0

Hmm. Pero si hiciera MyNum.new (2) + MyNum.new (3), ¿no recuperaría un Fixnum en lugar de una instancia de MyNum? Creo que debe envolver @ number.send en MyNum.new –

+0

Actualicé mi respuesta para asegurarme de que devuelva MyNum si la respuesta original fue numérica. –

+0

¿Se puede implementar MyNum de manera que MyNum.new (5) == 5 AND 5 == MyNum.new (5)? – rcrogers

2

¿No podría extender FixNum en sí? Como ...

class Fixnum 
    def even? 
    self % 2 == 0 
    end 
end 

42.even? 
+1

Podría, pero preferiría no hacerlo. Además, Fixnum no tiene #new, y necesito poder agregar funcionalidad para #initialize. – cloudhead

+1

Monkey-patching se debe utilizar con cuidado. Contaminar una clase básica de Ruby solo para un caso de uso específico puede ser peligroso. –

4

IIRC, la aplicación principal de Ruby almacena fixnums como valores inmediatos, utilizando algunas de las bajas bits de la palabra para etiquetar como un Fixnum en lugar de un puntero a un objeto en el montón. Es por eso que, en una máquina de 32 bits, los Fixnums solo tienen 29 bits (o lo que sea) en lugar de una palabra completa.

Por lo tanto, debido a eso, no puede agregar métodos a una sola "instancia" de Fixnum, y no puede crear una subclase.

Si tiene una clase "fija", probablemente tendrá que crear una clase que tenga una variable de instancia Fixnum, y reenviar las llamadas al método de forma adecuada.

+0

ah veo. ¿Hay alguna otra clase que pueda subclasificar? Numeric tiene un #new, pero no toma ningún argumento, así que supongo que es una clase abstracta. – cloudhead

+0

Hmm. No he tocado a Ruby por un tiempo, y no recuerdo exactamente cómo se distribuye el árbol de la clase numérica. –

+0

El único candidato obvio es BigDecimal. –

Cuestiones relacionadas