我有以下课程:
class A
X = %w(a b c)
end
如何使用A
中的值为类X
创建静态变量列表,以便最终得到与以下内容相同的内容:
class A
a = 1
b = 2
c = 3
end
我发现可以使用define_method
定义方法,但我不太了解如何为变量执行此操作。
答案 0 :(得分:4)
不幸的是,你想要的是AFAIK是不可能的。您根本无法动态地将局部变量引入范围。你可能想做这样的事情:
class A
X = %w(a b c)
end
class A
bnd = binding
X.each.with_index(1) do |var, i|
bnd.local_variable_set(var, i)
end
end
但那不会奏效。当您使用local_variable_set
创建 new 变量时,该变量将仅存在于Binding
对象中,而不在Binding
创建的范围内。
class A
bnd = binding
X.each.with_index(1) do |var, i|
eval("#{var} = #{i}", bnd)
end
end
这也不会奏效。实际上,它只是等同于第一个。
好的,所以你想:"让我们不要使用Binding
,然后,只是简单地eval
":
class A
X.each.with_index(1) do |var, i|
eval("#{var} = #{i}")
end
end
不,这也不起作用。局部变量仍然仅在eval
内创建,但它们不会泄露到外面。 (他们在1.8岁及以上的时候发生泄漏,但他们已经不再在1.9+了。)事实上,即使他们确实被创建了,他们也会在块的范围内创建。因此,您必须使用for
/ in
代替。
另请注意,即使 if 您设法将局部变量注入范围,它们仍然是局部变量:您无法从其他任何位置访问它们。 (除非你以某种方式设法抓住Binding
并致电local_variable_get
。)
使 更有意义制作方法,这更容易:
class A
X.each.with_index(1) do |var, i|
define_singleton_method(:var) do i end
end
end
现在,也可以从范围之外访问它们:
A.a # => 1
或使用有点模糊的方法使用范围解析运算符调用语法:
A::a # => 1
当然,因为它们总是返回相同的值,为什么不将它们设为常量?
class A
X.each.with_index(1) do |var, i|
const_set(var.upcase, i)
end
end
答案 1 :(得分:3)
常量定义如下(它们必须以大写字母开头):
class A
A = 1
B = 2
C = 3
end
A::A #=> 1
A::B #=> 2
A::C #=> 3
要动态定义它们,请使用const_set
:
class A
%w(A B C).each.with_index(1) { |c, i| const_set(c, i) }
end
答案 2 :(得分:1)
有一些元编程疯狂,你可以做类似
的事情 class A
class << self
def A.X(args)
puts "Creating methods"
args.each do |arg|
define_singleton_method(arg) {
if class_variable_defined? "@@#{arg}"
class_variable_get("@@#{arg}")
else
nil
end
}
define_singleton_method("#{arg}=") { |val|
class_variable_set("@@#{arg}", val)
}
end
end
end
end
允许你这样做
class A
X %w(a b c)
A.a = 1
A.b = 2
A.c = 3
end
需要使用A.a,A.b等前缀,因为有一些ruby语法的东西