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

面试题 相关文章推荐
为什么要优先使用同步代码块而不是同步方法?
Jan 30 面试题
如何启动时不需输入用户名与密码
May 09 面试题
如何提高JDBC的性能
Apr 30 面试题
名词解释型面试题(主要是网络)
Dec 27 面试题
Windows和Linux动态库应用异同
Jul 28 面试题
Python文件操作的面试题
Jun 22 面试题
sleep()方法和wait()方法的区别是什么
Nov 17 面试题
垃圾回收的优点和原理
May 16 面试题
shell的种类有哪些
Apr 15 面试题
如何现实servlet的单线程模式
Aug 05 面试题
Servlet如何得到客户端机器的信息
Oct 17 面试题
J2EE中常用的名词进行解释
Nov 09 面试题
介绍一下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 求质素(素数) 的实现代码
2011/04/12 PHP
PHP中常用的输出函数总结
2014/09/22 PHP
Codeigniter框架实现获取分页数据和总条数的方法
2014/12/05 PHP
Yii框架用户登录session丢失问题解决方法
2017/01/07 PHP
jQuery Ajax方法调用 Asp.Net WebService 的详细实例代码
2011/04/27 Javascript
用JQuery模仿淘宝的图片放大镜显示效果
2011/09/15 Javascript
jquery乱码与contentType属性设置问题解决方案
2013/01/07 Javascript
模拟电子签章盖章效果的jQuery插件源码
2013/06/24 Javascript
js unicode 编码解析关于数据转换为中文的两种方法
2014/04/21 Javascript
jQuery实现的类似淘宝网站搜索框样式代码分享
2015/08/24 Javascript
WordPress中鼠标悬停显示和隐藏评论及引用按钮的实现
2016/01/12 Javascript
三种Node.js写文件的方式
2016/03/08 Javascript
如何学JavaScript?前辈的经验之谈
2016/12/28 Javascript
微信小程序 实战程序简易新闻的制作
2017/01/09 Javascript
从零学习node.js之express入门(六)
2017/02/25 Javascript
纯js实现图片匀速淡入淡出效果
2017/08/22 Javascript
vue实现商城上货组件简易版
2017/11/27 Javascript
基于JavaScript中标识符的命名规则介绍
2018/01/06 Javascript
mint-ui 时间插件使用及获取选择值的方法
2018/02/09 Javascript
浅谈React中的元素、组件、实例和节点
2018/02/27 Javascript
JS实现遍历不规则多维数组的方法
2018/03/21 Javascript
详解小程序如何避免多次点击,重复触发事件
2019/04/08 Javascript
详解如何在Vue项目中导出Excel
2019/04/19 Javascript
vue跳转方式(打开新页面)及传参操作示例
2020/01/26 Javascript
[02:16]卖萌的僵尸 DOTA2神话信使飞僵小宝来袭
2014/03/24 DOTA
Python实现的异步代理爬虫及代理池
2017/03/17 Python
Python机器学习库scikit-learn安装与基本使用教程
2018/06/25 Python
Pycharm如何打断点的方法步骤
2019/06/13 Python
Flask框架学习笔记之路由和反向路由详解【图文与实例】
2019/08/12 Python
如何使用html5与css3完成google涂鸦动画
2012/12/16 HTML / CSS
AmazeUI 单选框和多选框的实现示例
2020/08/18 HTML / CSS
采购部岗位职责
2013/11/24 职场文书
弄虚作假心得体会
2014/09/10 职场文书
付款证明格式范文
2015/06/19 职场文书
Python实战之用tkinter库做一个鼠标模拟点击器
2021/04/27 Python
漫画「古见同学有交流障碍症」第25卷封面公开
2022/03/21 日漫