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...

面试题 相关文章推荐
Java中实现多态的机制
Aug 09 面试题
北承题目(C++)
May 16 面试题
写一个在SQL Server创建表的SQL语句
Mar 10 面试题
介绍一下SQL中union,intersect和minus
Apr 05 面试题
新大陆软件面试题
Nov 24 面试题
linux面试题参考答案(5)
Nov 05 面试题
港湾网络笔试题
Apr 19 面试题
外包公司软件测试工程师
Nov 01 面试题
什么是SCM(软件配置管理)
Aug 16 面试题
如何清空Session
Feb 23 面试题
Unix/Linux开发面试题
Aug 16 面试题
Java面试题冲刺第十五天--设计模式
Aug 07 面试题
介绍一下Ruby的特点
Jan 20 #面试题
JPA的优势都有哪些
Jul 04 #面试题
J2EE中的容器都包括哪些
Aug 21 #面试题
J2EE面试题
Mar 14 #面试题
J2EE包括哪些技术
Nov 25 #面试题
J2EE的优越性主要表现在哪些方面
Mar 28 #面试题
J2EE面试题集锦(附答案)
Aug 16 #面试题
You might like
Mysql的GROUP_CONCAT()函数使用方法
2008/03/28 PHP
解析php通过cookies获取远程网页的指定代码
2013/06/25 PHP
Laravel 5 学习笔记
2015/03/06 PHP
PHP 根据key 给二维数组分组
2016/12/09 PHP
PHP的介绍以及优势详细分析
2019/09/05 PHP
js 日期转换成中文格式的函数
2009/07/07 Javascript
合并table相同单元格的jquery插件分享(很精简)
2011/06/20 Javascript
JS+CSS实现自动改变切换方向图片幻灯切换效果的方法
2015/03/02 Javascript
原生JavaScript编写俄罗斯方块
2015/03/30 Javascript
浅谈jQuery构造函数分析
2015/05/11 Javascript
javascript实现下拉提示选择框
2015/12/29 Javascript
解析js如何获取css样式
2016/12/11 Javascript
深入理解javascript函数参数与闭包
2016/12/12 Javascript
简单实现js无缝滚动效果
2017/02/05 Javascript
基于Bootstrap的网页设计实例
2017/03/01 Javascript
js/jq仿window文件夹移动/剪切/复制等操作代码
2017/03/08 Javascript
react开发中如何使用require.ensure加载es6风格的组件
2017/05/09 Javascript
vue.js全局API之nextTick全面解析
2017/07/07 Javascript
jQuery中常用动画效果函数知识点整理
2018/08/19 jQuery
elementUI 设置input的只读或禁用的方法
2018/10/30 Javascript
用vscode开发vue应用的方法步骤
2019/05/06 Javascript
[03:13]DOTA2-DPC中国联赛1月25日Recap集锦
2021/03/11 DOTA
Python自动重试HTTP连接装饰器
2015/04/28 Python
python利用matplotlib库绘制饼图的方法示例
2016/12/18 Python
使用python在本地电脑上快速处理数据
2017/06/22 Python
Python实现的圆形绘制(画圆)示例
2018/01/31 Python
html5用video标签流式加载的实现
2020/05/20 HTML / CSS
德国珠宝和手表在线商店:VALMANO
2019/03/24 全球购物
Athleta官网:购买女士瑜伽服、技术运动服和休闲运动服
2020/11/12 全球购物
单位刻章介绍信范文
2014/01/11 职场文书
国培计划培训感言
2014/03/11 职场文书
爱我中华演讲稿
2014/05/20 职场文书
银行业务授权委托书
2014/10/10 职场文书
批评与自我批评发言稿
2014/10/15 职场文书
关于军训的感想
2015/08/07 职场文书
详解CSS故障艺术
2021/05/25 HTML / CSS