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

面试题 相关文章推荐
求网格中的黑点分布
Nov 06 面试题
static全局变量与普通的全局变量有什么区别?static局部变量和普通局部变量有什么区别?static函数与普通函数有什么区别?
Feb 22 面试题
数据库方面面试题
Apr 22 面试题
.net开发工程师面试题
Feb 25 面试题
WEB控件及HTML服务端控件能否调用客户端方法?如果能,请解释如何调用?
Aug 25 面试题
什么是Smart Navigation?
Jul 03 面试题
linux系统都有哪些运行级别
Apr 15 面试题
广州喜创信息技术有限公司JAVA软件工程师笔试题
Oct 17 面试题
EJB的角色和三个对象
Dec 31 面试题
有abstract方法的类一定要用abstract修饰吗
Mar 14 面试题
Servlet方面面试题
Sep 28 面试题
Java面试题冲刺第十八天--Spring框架3
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
php源码分析之DZX1.5加密解密函数authcode用法
2015/06/17 PHP
WordPress中调试缩略图的相关PHP函数使用解析
2016/01/07 PHP
win7安装php框架Yii的方法
2016/01/25 PHP
WordPress分页伪静态加html后缀
2016/06/08 PHP
TP5框架实现签到功能的方法分析
2020/04/05 PHP
JavaScript面象对象设计
2008/04/28 Javascript
Javascript打印网页部分内容的脚本
2008/11/17 Javascript
为指定元素增加样式的js代码
2009/12/09 Javascript
JavaScript 模拟用户单击事件
2009/12/31 Javascript
javascript中的array数组使用技巧
2010/01/31 Javascript
AngularJS基础知识笔记之过滤器
2015/05/10 Javascript
一个字符串中出现次数最多的字符 统计这个次数【实现代码】
2016/04/29 Javascript
JavaScript的Backbone.js框架入门学习指引
2016/05/07 Javascript
将json转换成struts参数的方法
2016/11/08 Javascript
微信小程序 图片等比例缩放(图片自适应屏幕)
2016/11/16 Javascript
获取今天,昨天,本周,上周,本月,上月时间(实例分享)
2017/01/04 Javascript
setTimeout函数的神奇使用
2017/02/26 Javascript
详解使用webpack打包编写一个vue-toast插件
2017/11/08 Javascript
微信小程序实现单列下拉菜单效果
2019/04/25 Javascript
用js简单提供增删改查接口
2019/05/12 Javascript
[47:45]Liquid vs OG 2018国际邀请赛小组赛BO2 第二场 8.16
2018/08/17 DOTA
[32:39]完美世界DOTA2联赛循环赛 Forest vs Inki BO2第一场 11.04
2020/11/04 DOTA
Python中dictionary items()系列函数的用法实例
2014/08/21 Python
Python如何判断数独是否合法
2016/09/08 Python
django中的HTML控件及参数传递方法
2018/03/20 Python
python实现自动登录
2018/09/17 Python
python+unittest+requests实现接口自动化的方法
2018/11/29 Python
Python pandas DataFrame操作的实现代码
2019/06/21 Python
pycharm新建一个python工程步骤
2019/07/16 Python
python3获取当前目录的实现方法
2019/07/29 Python
澳大利亚运动鞋零售商:The Athlete’s Foot
2018/11/04 全球购物
Linux上比较文件的命令都有哪些
2013/09/28 面试题
初任培训自我鉴定
2013/10/07 职场文书
大学自荐信
2013/12/12 职场文书
传播学专业毕业生自荐书
2014/07/01 职场文书
“四风”问题整改措施和努力方向
2014/09/20 职场文书