所以我知道你可以说Kernel.const_get(“ClassName”)并且你将获得字符串在名称中对应的类。但是变量怎么样?有办法吗?
test = "heyas"
some_method_here("test") #=> "heyas"
非常感谢
事实是我需要更复杂的代码,真实的例子:
class User
class Validations
class << self
def username_len
return u.len > 3 and u.len < 22
end
# ...
end
end
def validate(u,e,p)
[:u, :e, :p].each do |v|
Validations.send(:define_singleton_method, v, lambda { eval(v.to_s) }) # see this line
end
#other code to run validations
end
end
所以你看,没有更好的方法,是吗?
答案 0 :(得分:4)
不,只有class_variable_get
,instance_variable_get
和const_get
。没有local_variable_get
。但它无论如何都没有意义:局部变量是当前方法体,模块体,类体或脚本体的局部变量,这就是为什么它们称为“局部”变量,毕竟!您只是无法从其他方法访问它们。
有办法吗?
test = "heyas" some_method_here("test") #=> "heyas"
不,没有办法做到这一点。并且不可能是一种方法。 test
是本地变量,这意味着当前脚本正文中只存在 。 不存在于some_method_here
的正文中。这是局部变量的整点:在任何情况下,你都不可能从其他地方访问它们。
关于你对另一个答案的评论:
def my_func(str) var_a = 'hey' var_b = 'ah' return some_method_here(str) end #=> should return the corresponding variable's value, e.g. my_func('var_a') #=> 'hey'
同样,这个不可能工作,因为局部变量的整点是无法从其他任何地方访问 。
但是有一个非常简单的变体可以完全满足您的需求:
def my_func(str)
{
'var_a' => 'hey',
'var_b' => 'ah'
}[str]
end
#=> should return the corresponding variable's value, e.g. my_func('var_a')
#=> 'hey'
这当然可以进一步简化为:
my_func = {'var_a' => 'hey', 'var_b' => 'ah'}
#=> should return the corresponding variable's value, e.g. my_func['var_a']
#=> 'hey'
鉴于您只能传递有限数量的不同选项,最好使用符号代替:
my_func = {var_a: 'hey', var_b: 'ah'}
#=> should return the corresponding variable's value, e.g. my_func[:var_a]
#=> 'hey'
你要问的基本上是:传递钥匙,获取价值。这完全 Hash
是什么。
def validate(u, e, p)
local_variables.zip(local_variables.map {|var|
eval(var.to_s)
}).each {|var, val|
Validations.send(:define_singleton_method, var) { val }
}
end
但是,我认为设计存在严重问题。您根据User::Validations
的不同实例覆盖User
的单例方法。根据 singleton 方法的定义,系统中只能有一个副本。但是您有User
的许多不同实例,每次调用User#validate
时,它都会覆盖 {em}仅 副本User::Validations.u
, User::Validations.e
和User::Validations.p
,对于整个系统,他们的行为将完全不同。
换句话说,您正在基于单个实例更改整个系统的行为。并且可以有多个实例,每次都会改变系统的行为。
只是不能是正确的。
u1 = User.new
u1.validate('u1', :e1, 1)
p User::Validations.u, User::Validations.e, User::Validations.p
# => 'u1'
# => :e1
# => 1
u2 = User.new
u2.validate('U2', :E2, 2.0)
# => warning: method redefined; discarding old u
# => warning: method redefined; discarding old e
# => warning: method redefined; discarding old p
# ^^^^^^^^^^^^^^^^
# Oops!
p User::Validations.u, User::Validations.e, User::Validations.p
# => 'U2'
# => :E2
# => 2.0
# ^^^
# Completely different results for the exact same arguments
答案 1 :(得分:3)
也许我错过了什么,但你为什么不能test
来获得它的价值呢?如果要定义实例变量,则为instance_variable_get。
编辑:正如我在下面的评论中所提到的,你可以做到
def my_func(str); var_a="hey"; var_b="ah"; eval str; end
my_func('var_a') #=> "hey"
但这对我来说似乎有些疯狂,如果不是很疯狂的话。
答案 2 :(得分:2)
试试这个:
def validate(u,e,p)
[[:u, u], [:e, e], [:p, p]].each do |v|
Validations.send(:define_singleton_method, v.first, lambda { v.last })
end
end
或强>
def validate(u,e,p)
{:u => u, :e => e, :p => p}.each do |k, v|
Validations.send(:define_singleton_method, k, lambda { v })
end
end
答案 3 :(得分:1)
Binding可以访问您的局部变量,因此您可以使用绑定#eval
来执行此操作eval("#{var_name}")
会做到的。显然不要使用不受信任的输入。如果要避免未定义变量的错误,可以使用:
eval("#{var_name}") if eval("defined?(#{var_name})") == 'local-variable'
E.g。
test = 'heyas'
var_name = :test
eval("#{var_name}") if eval("defined?(#{var_name})") == 'local-variable' #=> "heyas"
var_name = :not_set
eval("#{var_name}") if eval("defined?(#{var_name})") == 'local-variable' #=> "nil"
在边缘红宝石上,这些定义如下:
Binding#local_variable_defined?
Binding#local_variable_get
Binding#local_variable_set
因此,在将来的版本中,您可能会直接使用这些调用。