在Python中,我可以轻松地修饰方法,以便记住它们的结果:
def store(self):
a = line1()
b = line2(a)
return line3(b)
=>
from lazy import lazy
@lazy
def store(self):
a = line1()
b = line2(a)
return line3(b)
Ruby中是否有一些类似的习惯用法只计算一次方法结果?
答案 0 :(得分:3)
在Ruby中,这通常称为memoization,它采用天真的形式:
def store
@store ||= begin
a = line1
b = line2(a)
line3(b)
end
end
如果在多线程环境中使用此代码,则存在一些重要问题,这就是为什么有宝石可以管理它并确保您的惰性初始化程序只运行一次,如果这是一个问题。
答案 1 :(得分:2)
另一个适用于false
和nil
的选项:
def store
unless defined?(@store)
a = line1
b = line2(a)
@store = line3(b)
end
@store
end
答案 2 :(得分:2)
不是真的。有一个运算符(||=
)仅在左操作数为假(nil
或false
)时才分配值。通常使用它和实例变量就可以了。
Memoist和Memoizable是经常用于此目的的宝石。
但我的猜测是你的问题更普遍 - 你如何在ruby中实现方法装饰器?
class Module
def decorate(method_name, &decoration)
undecorated_method = instance_method(method_name)
define_method(method_name) do
decoration.call(&undecorated_method.bind(self))
end
end
def memoize(method_name)
@values ||= {}
decorate(method_name) do |&evaluator|
unless @values.key?(method_name)
@values[method_name] = evaluator.call
end
@values[method_name]
end
end
end
class SuperComputer
memoize def answer
puts "Pending... 7½ million years remaining."
42
end
end
deep_mind = SuperComputer.new
deep_mind.answer # => 42 (and prints)
deep_mind.answer # => 42 (doesn't print)
现在,从这个实现(args,kwargs,块,每个实例的memoization等)中可以得到很多东西,但是它应该让你大致了解如何在不需要更改语言的情况下实现装饰器本身。