2014-09-27 69 views
1
class Foo 
end 

class_name = 'Foo' 
f = eval(class_name).new 
#<Foo:0x007fd3e273ed68> 

本示例创建Foo的预期实例。如何在Ruby中通过变量实例化对象?

该类预计会被定义,但我们想要实例化一个在class_name中定义的类的对象。

class_name值来自用户的,所以上面的代码是一个非常糟糕的主意™ ...

回答

1

一个类没什么特别的。它只是一个分配给变量的对象,或者在你显示的代码中是一个常量。所以,你可以使用相同的元编程的方法来从一个变量检索类,你会与任何其他对象使用:Object#instance_variable_getModule#class_variable_getBinding#local_variable_getThread#thread_variable_get,或者其中一个是适用于这种情况Module#const_get

class Foo; end 

class_name = 'Foo' 
foo = Object.const_get(class_name).new 
#=> #<Foo:0x007fd3e273ed68> 

foo = self.class.const_get(class_name).new 
#=> #<Foo:0x007fd3e273ed68> 

注意,在其他两个答案的代码只能小心:他们在Module类,因为你有实际上ObjectModule继承Object定义Foo只适用的情况下查找Foo。如果你没有在祖先但在Module同级定义Foo,然后在其他两个答案的代码是行不通的:

module Bar; class Foo; end end 

Module.const_get(:Foo) 
# NameError: uninitialized constant Module::Foo 

Bar.const_get(:Foo) 
# => Bar::Foo 

如果你想const_get的运行方式正常常量查找同样会,你需要在你想要真正查看它的类/模块上调用它,而不是在某个随机类上。

+0

哇,这是我正在寻找的答案。谢谢。你有什么资源可以推荐用于Metaprogramming? – 2014-09-28 12:06:18

+1

Ruby程序员不倾向于将元编程看作任何特殊的东西。这对他们来说只是正常编程的一个自然部分,所以他们通常也不会考虑为它编写特殊资源。用于Ruby编程的任何资源也将涵盖元编程,即使在最开始时也是如此:'attr_accessor'是一种生成方法的方法,每次使用'attr_accessor'时,都会执行元编程。然而,如果你可以放纵自己独特的风格,那么[为什么这个幸运儿](https://wikipedia.org/wiki/Why_the_lucky_stiff)的作品,在解释元编程方面非常擅长。 – 2014-09-28 13:14:51

+1

例如,请参阅[*为什么(Poignant)Ruby指南](http://mislav.uniqpath.com/poignant-guide/),特别是[* Dwemthy's Array *](http://mislav.uniqpath。com/poignant-guide/dwemthy /)(一个使用Ruby元编程的地下城游戏!)另外,总是有Paolo Perrotta的[*元程序Ruby *](https://pragprog.com/book/ppmetr2/metaprogramming-ruby -2)。但是,我不能说任何这些资源,因为我自己实际上是通过Ruby编程来学习Ruby Metaprogramming的,因为这很自然。 – 2014-09-28 13:18:43

2

退房Module::const_get

class Foo 
end 

class_name = 'Foo' 
myClass = Module.const_get(class_name) 
myClass.new 

当然,顾名思义,你可以用它来获得任何形式的常数。所以,可能是明智的检查,如果你得到一个类回:

SOME_CONST = 5 
Module.const_get('SOME_CONST').is_a? Class # => false 
Module.const_get('String').is_a? Class  # => true 
1

const_get可以得到一个参考类

Module.const_get(:Foo).new 

Module.const_get('Foo').new 

注:< 1.9它只搜索当前模块。