Ruby如何实现动态方法调用


Posted in 面试题 onNovember 18, 2012
在Ruby中,有多种方法可以实现方法的动态调用。
1. 使用send方法
第一种实现动态方法调用是使用send方法,send方法在Object类中定义,方法的第一个参数是一个符号用来表示所要调用的方法,后面则是所调用方法需要的参数。
“This is a dog1″.send(:length) => 14
上面的代码中通过send方法去对一个字符串执行length操作,返回字符串的长度。

class TestClass
def hello(*args)
”Hello ” + args.join(‘ ‘)
end
end

a = TestClass.new
puts a.send :hello, “This”, “is”, “a”, “dog!”

执行结果为:
Hello This is a dog!

2. 使用Method类和UnboundMethod类
另一种实现动态方法调用是使用Object类的method方法,这个方法返回一个Method类的对象。我们可以使用call方法来执行方法调用。
test1 = “This is a dog1″.method(:length)
test1.call => 14

class Test
def initialize(var)
@var = var
end

def hello()
”Hello, @var = #{@var}”
end
end

k = Test.new(10)
m = k.method(:hello)
m.call #=> “Hello, @iv = 99″

l = Test.new(‘Grant’)
m = l.method(“hello”)
m.call #=> “Hello, @iv = Fred”

可以在使用对象的任何地方使用method对象,当调用call方法时,参数所指明的方法会被执行,这种行为有些像C语言中的函数指针。你也可以把method对象作为一个迭代器使用。
def square(a)
a*a
end

mObj = method(:square)
[1, 2, 3, 4].collect(&mObj) => [1 4 9 16]

Method对象都是和某一特定对象绑定的,也就是说你需要通过某一对象使用Method对象。你也可以通过UnboundMethod类创建对象,然后再把它绑定到某个具体的对象中。如果UnboundMethod对象调用时尚未绑定,则会引发异常。
class Double
def get_value
2 * @side
end

def initialize(side)
@side = side
end
end

a = Double.instance_method(:get_value) #返回一个UnboundMethod对象
s = Double.new(50)
b = a.bind(s)
puts b.call

执行结果为:
100

看下面一个更具体的例子:
class CommandInterpreter
def do_2() print “This is 2\n”; end
def do_1() print “This is 1\n”; end
def do_4() print “This is 4\n”; end
def do_3() print “This is 3\n”; end

Dispatcher = {
?2 => instance_method(:do_2),
?1 => instance_method(:do_1),
?4 => instance_method(:do_4),
?3 => instance_method(:do_3)
}

def interpret(string)
string.each_byte {|i| Dispatcher[i].bind(self).call }
end
end

interpreter = CommandInterpreter.new
interpreter.interpret(’1234′)

执行结果为:
This is 1
This is 2
This is 3
This is 4

3. 使用eval方法
我们还可以使用eval方法实现方法动态调用。eval方法在Kernel模块中定义,有多种变体如class_eval,module_eval,instance_eval等。Eval方法将分析其后的字符串参数并把这个字符串参数作为Ruby代码执行。
str = “Hello”
eval “str + ‘ World!’” => Hello World!

sentence = %q{“This is a test!”.length}
eval sentence => 15
当我们在使用eval方法时,我们可以通过eval方法的第二个参数指明eval所运行代码的上下文环境,这个参数可以是Binding类对象或Proc类对象。Binding类封装了代码在某一环境运行的上下文,可以供以后使用。
class BindingTest
def initialize(n)
@value = n
end

def getBinding
return binding() #使用Kernel#binding方法返回一个Binding对象
end
end

obj1 = BindingTest.new(10)
binding1 = obj1.getBinding
obj2 = BindingTest.new(“Binding Test”)
binding2 = obj2.getBinding

puts eval(“@value”, binding1) #=> 10
puts eval(“@value”, binding2) #=> Binding Test
puts eval(“@value”) #=> nil

可以看到上述代码中,@value在binding1所指明的上下文环境中值为10,在binding2所指明的上下文环境中值为Binding Test。当eval方法不提供binding参数时,在当前上下文环境中@value并未定义,值为nil。

Tags in this post...

面试题 相关文章推荐
PHP笔试题
Feb 22 面试题
什么是接口(Interface)?
Feb 01 面试题
Java基础知识面试要点
Jul 29 面试题
C面试题
Oct 08 面试题
一些.net面试题
Oct 06 面试题
动态密码技术
Oct 18 面试题
常用UNIX 命令(Linux的常用命令)
Dec 26 面试题
软件测试工程师结构化面试题库
Nov 23 面试题
几个常见的消息中间件(MOM)
Jan 08 面试题
MVC的各个部分都有那些技术来实现?如何实现?
Apr 21 面试题
金额转换,阿拉伯数字的金额转换成中国传统的形式如:(¥1011)-> (一千零一拾一元整)输出
May 29 面试题
值传递还是引用传递
Feb 08 面试题
介绍一下Ruby的特点
Jan 20 #面试题
JPA的优势都有哪些
Jul 04 #面试题
J2EE中的容器都包括哪些
Aug 21 #面试题
J2EE面试题
Mar 14 #面试题
J2EE包括哪些技术
Nov 25 #面试题
J2EE的优越性主要表现在哪些方面
Mar 28 #面试题
J2EE面试题集锦(附答案)
Aug 16 #面试题
You might like
php中文本数据翻页(留言本翻页)
2006/10/09 PHP
PHP安全配置详细说明
2011/09/26 PHP
比较简单实用的PHP无限分类源码分享(思路不错)
2011/10/13 PHP
php查询mssql出现乱码的解决方法
2014/12/29 PHP
PHP基本语法实例总结
2016/09/09 PHP
遍历echsop的region表形成缓存的程序实例代码
2016/11/01 PHP
新手入门常用代码集锦
2007/01/11 Javascript
网上应用的一个不错common.js脚本
2007/08/08 Javascript
YUI 读码日记之 YAHOO.lang.is*
2008/03/22 Javascript
一段实现页面上的图片延时加载的js代码
2010/02/11 Javascript
jQuery学习总结之jQuery事件
2014/06/30 Javascript
jQuery实现折线图的方法
2015/02/28 Javascript
JS中使用变量保存arguments对象的方法
2016/06/03 Javascript
javascript 内置对象及常见API详细介绍
2016/11/01 Javascript
jQuery模拟爆炸倒计时功能实例代码
2017/08/21 jQuery
JS开发 富文本编辑器TinyMCE详解
2019/07/19 Javascript
jQuery实现弹幕特效
2019/11/29 jQuery
[02:43]中国五虎出征TI3视频
2013/08/02 DOTA
[42:23]完美世界DOTA2联赛PWL S3 Forest vs Rebirth 第二场 12.10
2020/12/13 DOTA
python实现微信发送邮件关闭电脑功能
2018/02/22 Python
Django基础知识与基本应用入门教程
2018/07/20 Python
使用python3实现操作串口详解
2019/01/01 Python
详解django2中关于时间处理策略
2019/03/06 Python
如何在Python中实现goto语句的方法
2019/05/18 Python
flask/django 动态查询表结构相同表名不同数据的Model实现方法
2019/08/29 Python
Python 读取用户指令和格式化打印实现解析
2019/09/02 Python
Pytorch 实现sobel算子的卷积操作详解
2020/01/10 Python
python中数字是否为可变类型
2020/07/08 Python
Python os库常用操作代码汇总
2020/11/03 Python
欧舒丹英国官网:购买欧舒丹护手霜等明星产品
2017/01/17 全球购物
init进程的作用
2012/04/12 面试题
经济管理毕业生求职信
2014/03/15 职场文书
幼儿园见习报告范文
2014/10/30 职场文书
活动总结书怎么写
2015/05/11 职场文书
文艺演出主持词
2015/07/01 职场文书
React forwardRef的使用方法及注意点
2021/06/13 Javascript