我在Ruby中有一个包含一个方法和一个变量的模块:
module ApplicationHelper
@var1 = MyModel::CONST1.each_with_index.map { |item, i| [item, i] }
def method1 v1, v2, v3 = @var1[0]
#....
# access to @var1
end
end
我希望@var1
成为变量的原因是,如果它是一个方法,我会在method1
内每次访问它时对其进行评估。这是不合理的,因此,我希望它只被评估一次。
但是,当我通过ajax(使用它的基于ajax的对话框)调用此method1
(它是一个辅助方法)时,@ var1结果为零。同样,在第一页加载期间,它按照我的预期填写。
我该怎么办?
答案 0 :(得分:2)
你的背景不一样(见):
module ApplicationHelper
p self # => ApplicationHelper
def method1
p self # => #<OtherClass:0x007fbe032cf6f0> an instance of an object
end
end
Ruby不像Java一样工作,因为您无法像在模块(或类)的上下文中那样设置对象实例变量。在您的代码中,@var1 = MyModel::CONST1.each_with_index.map { |item, i| [item, i] }
在任何实例上的实际模块对象var1
,不上定义实例变量ApplicationHelper
。
在Ruby中,当你只想定义一次变量时,我们使用||=
memoization技巧:
module ApplicationHelper
def method1
@var1 ||= MyModel::CONST1.each_with_index.map { |item, i| [item, i] }
end
end
这是一个利用第一次引用变量的事实,它将是nil
,而nil
在Ruby中被认为是fasely。所以上面这行是写作的捷径:
@var1 || @var1 = MyModel::CONST1.each_with_index.map { |item, i| [item, i] }
注意:请注意,如果@var1
可能是值nil
或false
,则每次都会对其进行重新评估。但是,在这种情况下。由于您使用的是Enumerable#map,因此如果没有商品,您将获得[]
,而不是nil
。因此,在这种情况下,使用情况将如预期一样。
第一次调用method1
时,边缘情况会出现问题,因为您正在使用它设置默认值。如果我们改为使用消息传递而不是直接变量访问,我们可以实现您的目标:
module ApplicationHelper
def method1(v1, v2, v3 = var1.first)
#....
# all further access to @var1 is done by passing the message var1
tmp = var1.select{ ... }
end
def var1
@var1 ||= MyModel::CONST1.each_with_index.map { |item, i| [item, i] }
end
end