0

我在 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 原来是 nil。同样,在第一页加载期间,它按我的预期填写。

我该怎么办?

4

1 回答 1

2

您的上下文不一样(请参阅):

module ApplicationHelper
  p self # => ApplicationHelper

  def method1
    p self # => #<OtherClass:0x007fbe032cf6f0> an instance of an object
  end
end

Ruby 不像 Java 那样工作,因为您不能像以前那样在模块(或类)的上下文中设置对象实例变量。在您的代码中,是在实际模块 object 上@var1 = MyModel::CONST1.each_with_index.map { |item, i| [item, i] }定义实例变量,而不是在任何实例上。var1ApplicationHelper

在 Ruby 中,当您只想定义一次变量时,我们使用||=记忆技巧:

module ApplicationHelper
  def method1
    @var1 ||= MyModel::CONST1.each_with_index.map { |item, i| [item, i] }
  end
end

这个技巧利用了这样一个事实,即您第一次引用一个变量时,它会在 Ruby 中被认为很容易nilnil所以上面这行是写法的捷径:

@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
于 2013-06-16T15:32:29.923 回答