如何“动态”设置变量值?

发布于 11-29 13:46 字数 779 浏览 1 评论 0原文

我正在使用 Ruby on Rails 3.0.9,并且尝试“动态”设置一些变量值。也就是说......

在我的模型文件中,我有:

attr_accessor :variable1, :variable2, :variable3


# The 'attributes' argument contains one or more symbols which name is equal to 
# one or more of the 'attr_accessor' symbols.

def set_variables(*attributes)

  # Here I should set to 'true' all ":variable<N>" attributes passed as symbol
  # in the 'attributes' array, but variable names should be interpolated in a 
  # string.
  # 
  # For example, I should set something like "prefix_#{':variable1'.to_s}_suffix".

end

如何将这些变量值设置为true


我尝试使用self.send (...) 方法,但我没有成功(但是,可能,我根本不知道如何使用该 send 方法...是否可以这样做我需要使用 send 方法?!)。

I am using Ruby on Rails 3.0.9 and I am trying to set "dynamically" some variable values. That is...

... in my model file I have:

attr_accessor :variable1, :variable2, :variable3


# The 'attributes' argument contains one or more symbols which name is equal to 
# one or more of the 'attr_accessor' symbols.

def set_variables(*attributes)

  # Here I should set to 'true' all ":variable<N>" attributes passed as symbol
  # in the 'attributes' array, but variable names should be interpolated in a 
  # string.
  # 
  # For example, I should set something like "prefix_#{':variable1'.to_s}_suffix".

end

How can I set those variable values to true?


I tried to use the self.send(...) method, but I did not succeed (but, probably, I don't know how to use at all that send method... is it possible do to that I need by using the send method?!).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

雨轻弹2024-12-06 13:46:00
attr_accessor :variable1, :variable2, :variable3

def set_variables(*attributes)
  attributes.each {|attribute| self.send("#{attribute}=", true)}
end
attr_accessor :variable1, :variable2, :variable3

def set_variables(*attributes)
  attributes.each {|attribute| self.send("#{attribute}=", true)}
end
南薇2024-12-06 13:46:00

以下是 sendinstance_variable_set 的基准比较:

require 'benchmark'

class Test
  VAR_NAME = '@foo'
  ATTR_NAME = :foo

  attr_accessor ATTR_NAME

  def set_by_send i
    send("#{ATTR_NAME}=", i)
  end

  def set_by_instance_variable_set i
    instance_variable_set(VAR_NAME, i)
  end
end

test = Test.new

Benchmark.bm do |x|
  x.report('send                 ') do
    1_000_000.times do |i|
      test.set_by_send i
    end
  end
  x.report('instance_variable_set') do
    1_000_000.times do |i|
      test.set_by_instance_variable_set i
    end
  end
end

时序为:(

      user     system      total        real
send                   1.000000   0.020000   1.020000 (  1.025247)
instance_variable_set  0.370000   0.000000   0.370000 (  0.377150)

使用 1.9.2 测量)

应该注意的是,仅在某些情况下(例如这种情况,使用使用 attr_accessor 定义的访问器)在功能上与 sendinstance_variable_set 等效。如果所涉及的访问器中有一些逻辑,就会有差异,您必须决定需要两者中的哪一个变体。 instance_variable_set 只是设置 ivar,而 send 实际上执行访问器方法,无论它做什么。

另请注意 - 这两种方法在另一个方面的行为有所不同:如果您 instance_variable_set 一个尚不存在的 ivar,它将被创建。如果您使用 send 调用不存在的访问器,则会引发异常。

Here's the benchmark comparison of send vs instance_variable_set:

require 'benchmark'

class Test
  VAR_NAME = '@foo'
  ATTR_NAME = :foo

  attr_accessor ATTR_NAME

  def set_by_send i
    send("#{ATTR_NAME}=", i)
  end

  def set_by_instance_variable_set i
    instance_variable_set(VAR_NAME, i)
  end
end

test = Test.new

Benchmark.bm do |x|
  x.report('send                 ') do
    1_000_000.times do |i|
      test.set_by_send i
    end
  end
  x.report('instance_variable_set') do
    1_000_000.times do |i|
      test.set_by_instance_variable_set i
    end
  end
end

And the timings are:

      user     system      total        real
send                   1.000000   0.020000   1.020000 (  1.025247)
instance_variable_set  0.370000   0.000000   0.370000 (  0.377150)

(measured using 1.9.2)

It should be noted that only in certain situations (like this one, with accessor defined using attr_accessor) are send and instance_variable_set functionally equivalent. If there is some logic in the accessor involved, there would be a difference, and you would have to decide which variant you would need of the two. instance_variable_set just sets the ivar, while send actually executes the accessor method, whatever it does.

Another remark - the two methods behave differently in another aspect: if you instance_variable_set an ivar which doesn't exist yet, it will be created. If you call an accessor which doesn't exist using send, an exception would be raised.

凑诗2024-12-06 13:46:00

您需要的方法是 instance_variable_set 所以在您的情况下:

def set_variables(*attributes)
  attributes.each {|attribute| self.instance_variable_set(attribute, true)}
end

The method you're after is instance_variable_set so in your case:

def set_variables(*attributes)
  attributes.each {|attribute| self.instance_variable_set(attribute, true)}
end
如梦亦如幻2024-12-06 13:46:00
def set_attributes(*attributes)
  attributes.each do |attr|
    self.send "#{attr}=", true
  end
end

请记住,在 Ruby 中,setter 方法名称以 = 结尾。

def set_attributes(*attributes)
  attributes.each do |attr|
    self.send "#{attr}=", true
  end
end

Remember that setter method names end with = in Ruby.

就像说晚安2024-12-06 13:46:00

我知道这个问题是针对 Rails 3 的,但是在搜索 Rails 4 关于“如何动态访问变量值”的答案时出现了这个问题。我在我的模型上对此进行了测试,它作为建议解决方案的替代方案效果很好:

def set_variables(*attributes)
  attributes.each {|attribute| self["#{attribute}"] = true}
end

I know the question was for Rails 3, but the question came up when searching for Rails 4 answers about "how to dynamically access variable values". I tested this on my model and it worked great as an alternative to the proposed solutions:

def set_variables(*attributes)
  attributes.each {|attribute| self["#{attribute}"] = true}
end
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文