Tengo una situación para Ruby, donde posiblemente sea necesario crear un objeto, pero no es seguro. Y como la creación del objeto puede ser costosa, no estoy demasiado ansioso por crearla. Creo que este es un caso claro para la carga lenta. ¿Cómo puedo definir un objeto que no se crea solo cuando alguien le envía un mensaje? El objeto se crearía en un bloque. ¿Hay alguna forma de carga/inicialización simple y diferida en Ruby? ¿Estas cosas son compatibles con algunas gemas, que proporcionan diferentes soluciones para varios casos de inicialización perezosa de objetos? Gracias por tus sugerencias!Evaluación diferida en Ruby
Respuesta
Hay dos formas.
El primero es dejar que el llamador maneje la creación de objetos perezosos. Esta es la solución más simple, y es un patrón muy común en código Ruby.
class ExpensiveObject
def initialize
# Expensive stuff here.
end
end
class Caller
def some_method
my_object.do_something
end
def my_object
# Expensive object is created when my_object is called. Subsequent calls
# will return the same object.
@my_object ||= ExpensiveObject.new
end
end
La segunda opción es dejar que el objeto se inicialice con pereza. Creamos un objeto delegado alrededor de nuestro objeto real para lograr esto. Este enfoque es un poco más complicado y no recomendado a menos que tenga un código de llamada existente que no pueda modificar, por ejemplo.
class ExpensiveObject # Delegate
class RealExpensiveObject # Actual object
def initialize
# Expensive stuff here.
end
# More methods...
end
def initialize(*args)
@init_args = args
end
def method_missing(method, *args)
# Delegate to expensive object. __object method will create the expensive
# object if necessary.
__object__.send(method, *args)
end
def __object__
@object ||= RealExpensiveObject.new(*@init_args)
end
end
# This will only create the wrapper object (cheap).
obj = ExpensiveObject.new
# Only when the first message is sent will the internal object be initialised.
obj.do_something
También es posible usar el stdlib delegate
para construir esta en la parte superior de.
En el primer ejemplo, necesito mantener la instancia de la clase de llamada. ¿Derecha? Pero, ¿cuál es la diferencia para mí, para mantener la instancia de la clase de llamada o para mantener la instancia de clase Expensive? – demas
En el primer ejemplo, la clase 'Caller' es solo un ejemplo de cómo * usar * la clase ExpensiveObject. La diferencia: introduzca la pereza donde * use * el 'ExpensiveObject' (simple), o introduzca la pereza en el' ExpensiveObject' * itself * (un poco más complicado). – molf
@molf: Siempre que anule 'method_missing' usted * debe * también anular' responder_ a? '(O preferiblemente' responder_ a_ perder? 'En 1.9.2). Ver http://blog.marc-andre.ca/2010/11/methodmissing-politely.html – Nemo157
Si desea evaluar perezosamente piezas de código, utilice un proxy:
class LazyProxy
# blank slate... (use BasicObject in Ruby 1.9)
instance_methods.each do |method|
undef_method(method) unless method =~ /^__/
end
def initialize(&lazy_proxy_block)
@lazy_proxy_block = lazy_proxy_block
end
def method_missing(method, *args, &block)
@lazy_proxy_obj ||= @lazy_proxy_block.call # evaluate the real receiver
@lazy_proxy_obj.send(method, *args, &block) # delegate unknown methods to the real receiver
end
end
A continuación, utilizar de esta manera:
expensive_object = LazyProxy.new { ExpensiveObject.new }
expensive_object.do_something
Usted puede utilizar este código para hacer la inicialización arbitrariamente compleja de cosas caras:
expensive_object = LazyProxy.new do
expensive_helper = ExpensiveHelper.new
do_really_expensive_stuff_with(expensive_helper)
ExpensiveObject.new(:using => expensive_helper)
end
expensive_object.do_something
¿Cómo funciona? Crea una instancia de un objeto LazyProxy que contiene instrucciones sobre cómo construir algún objeto costoso en un Proc. Si luego llama a algún método en el objeto proxy, primero crea una instancia del objeto caro y luego delega la llamada al método.
- 1. Evaluación diferida
- 2. Evaluación diferida en Clojure
- 3. Problema de evaluación diferida
- 4. Ruby Challenge - Método de encadenamiento y evaluación diferida
- 5. evaluación diferida con autoload vs require in ruby?
- 6. Ejecución diferida y evaluación entusiasta
- 7. buenas prácticas en C++ (evaluación diferida)
- 8. Evaluación diferida con lambda en Python
- 9. Eager evaluación/orden de aplicación y evaluación diferida/orden normal
- 10. C# expresiones lambda y evaluación diferida
- 11. ¿Mathematica 7 es compatible con la evaluación diferida?
- 12. ¿Cómo puedo implementar una clase con estado de evaluación diferida con dependencias internas en Java?
- 13. C: ¿hay una "evaluación diferida" cuando se usa el operador &&, como en C++?
- 14. Lista diferida de números primos
- 15. ¿Cómo puedo simular o probar mi funcionalidad de evaluación/ejecución diferida?
- 16. Ejecución diferida en C#
- 17. evaluación de la clase Ruby, validates_inclusion_of con datos dinámicos
- 18. ¿Cuál es la diferencia en la evaluación diferida del código en subrutinas para 5.8 de Perl contra 5.10 y 5.12?
- 19. Carga diferida en Knockout JS
- 20. SQL Server Boolean Evaluación de evaluación
- 21. Evaluación asíncrona en Mathematica
- 22. Lazy evaluación en Bash
- 23. evaluación en tiempo
- 24. La evaluación perezosa de argumentos suministrados
- 25. ¿Carga diferida del iframe?
- 26. Trayectoria completa retorcida, diferida
- 27. Python, lista diferida
- 28. ¿Biblioteca de carga diferida?
- 29. Evaluación Lightswitch
- 30. Evaluación booleana en una lambda
En lugar de enrollar el suyo, puede usar [lazy.rb] (https://github.com/mental/lazy). Hay algunos ejemplos de uso en el libro [Mejores prácticas de Ruby] (http://oreilly.com/catalog/9780596523015/), consulte la página 123 y hacia adelante. –