根据类名创建实例——Ruby实现 :: 梦想风暴
来源: BlogBus 原始链接: http://dreamhead.blogbus.com:80/logs/2006/10/3593586.html 存档链接: https://web.archive.org/web/20061109004546id_/http://dreamhead.blogbus.com:80/logs/2006/10/3593586.html
梦想风暴 一个小程序员的信口开河 << 长城一日游 | 主页 | 管窥Ruby——类的变量 >> 根据类名创建实例——Ruby实现 2006-10-16 在Ruby On Rails中文社区的的Ruby版上,karl问了一个有趣的问题,如何根据类名生成一个类的实例。 链接在这里: http://www.railscn.com/about2289.html 下面是一个Java语言的实现: public static Object createObject(String className) throws ClassNotFoundException, InstantiationException, IllegalAccessException { Class clazz = Class.forName(className); return clazz.newInstance(); } 在Ruby中怎么做呢?karl自己给出了第一种做法: str = 'String' eval "obj=#{str}.new" 这里利用了Ruby的动态语言的特性,在代码中执行代码。不过,照着尝试了一下,我有了一个疑问,如何使用生成的对象,也就是,我们如何利用这里的obj呢? 按照karl提供的方式,编写出这样的代码: str = 'String' eval "obj = #{str}.new" p obj 这里故意使用了p方法,因为对于一个空串,它可以打出"",而不是无声无息,便于查看。 这样的代码是无法运行的,异常如下: undefined local variable or method `obj' for main:Object (NameError) 然而,这段代码在irb中执行没有问题,这是irb和Ruby不兼容的一个地方。在《Programming Ruby》第二版中的第15章,谈及irb限制的时候,提到了这一点。 eval执行会有一个值,也就是它最后执行的语句的值,对应到这里就是obj的值。根据这个特性,改写得到了第二种做法,代码如下: str = 'Array' obj = eval "obj = #{str}.new" p obj 显然eval里的obj没有发挥什么作用,再修改一下: str = 'Array' obj = eval "#{str}.new" p obj 这样,我们就根据字符串创建出一个可用的对象。事实上,第一种方式也是可用的,不过,要obj在前面已经存在,只不过要稍做修改: obj = nil eval "obj = String.new" p obj qiezi的回帖给出了一个我认为最漂亮的一种做法: obj = eval(str).new 同样是利用eval,不同的是,这里是直接执行类名,结果是得到一个类对象。调用类的new方法就创建实例。这段代码看上去类似于一个普通的函数调用,很简洁。 对应到前面的Java函数,Ruby的实现就可以这样写: def create_obj(class_name) eval(class_name).new end UPDATE 故事有了新的进展,njmzhang提供了另外的方法,按照他的说法,这几乎是一种标准用法: c = Object.const_get("Array") s = c.new 这里利用到了一个事实,所有的类对象在Ruby中都是一个常量,所以,可以根据它的名字把这个常量提取出来。 除此之外,njmzhang还给出了另一种利用扩展实现的方法: c = Class.by_name("Array") 这里用到的扩展在 http://extensions.rubyforge.org/ 从方法的命名上来说,它比上一种方法更恰当一些。 算上这两种实现,我最喜欢的仍然是qiezi给出的那种方法。 dreamhead 发表于 2006-10-16 21:40 引用Trackback(0) | 编辑 Comments 发表评论 最近更新