一:proc / lambda
1.让我们分别以proc和lambda两种方式来定义代码块
2.2.2 :001 > a = proc { |x| x } => #<Proc:0x007fe62c31d610@(irb):1>2.2.2 :002 > a.call(2) => 22.2.2 :003 > b = lambda { |x| x } => #<Proc:0x007fe62c26fc68@(irb):3 (lambda)>2.2.2 :004 > b.call(3) => 3
2.proc和lambda有什么区别呢
(1)proc是一个代码块,而lambda更像一个方法
2.2.2 :005 > a.call => nil2.2.2 :006 > b.callArgumentError: wrong number of arguments (0 for 1) from (irb):3:in `block in irb_binding' from (irb):6:in `call' from (irb):6 from /Users/tnt29/.rvm/rubies/ruby-2.2.2/bin/irb:11:in `<main>'
todo: proc不传递任何参数也是可以的,返回nil,而lambda不传递参数就会报错
(2)
2.2.2 :007 > def method_a2.2.2 :008?> a = proc { return 3 }2.2.2 :009?> a.call2.2.2 :010?> 42.2.2 :011?> end => :method_a2.2.2 :012 > method_a => 3
todo: 在method_a这个方法内部,proc做为整个方法体直接返回了
2.2.2 :013 > def method_b2.2.2 :014?> b = lambda { return 5 }2.2.2 :015?> b.call2.2.2 :016?> 62.2.2 :017?> end => :method_b2.2.2 :018 > method_b => 6
todo: lambda把方法内都执行完毕了
总结:proc和lambda最主要的区别是:
lambda的行为和传统意义的ruby的method方法的性质的是一致的,因为上面无论是参数的区别还是返回值的区别,都是和一个正常的函数保持一致的。
而proc严格意义上是一个代码块,改变当前作用的上下文的解释顺序的
二:method / block
如何将一个方法做为参数传递呢?
2.2.2 :019 > method(:method_a).call => 3
比如面试官为了考验你对代码块的理解给你出了一个面试题,你怎么定义一个方法来实现计数器
实现代码如下:
2.2.2 :021 > def count2.2.2 :022?> a = 02.2.2 :023?> proc { a+=1 }2.2.2 :024?> end => :count2.2.2 :025 > x = count => #<Proc:0x007fe62be06eb0@(irb):23>2.2.2 :026 > x.call => 12.2.2 :027 > x.call => 22.2.2 :028 > x.call => 32.2.2 :029 > x.call => 42.2.2 :030 >
这是个什么原理呢?
因为代码块是可以保留它所在方法的作用域的,当然也就代表保留了上下文作用域的变量。
其实在ruby中有一个方法叫binding是返回作用域的
2.2.2 :031 > def hello2.2.2 :032?> y = 102.2.2 :033?> end => :hello2.2.2 :034 > hello => 102.2.2 :035 > yNameError: undefined local variable or method `y' for main:Object from (irb):35 from /Users/tnt29/.rvm/rubies/ruby-2.2.2/bin/irb:11:in `<main>'
我们加上binding试一下
2.2.2 :063 > def hello2.2.2 :064?> y = 112.2.2 :065?> binding2.2.2 :066?> end => :hello2.2.2 :067 > m = hello => #<Binding:0x007fe62d0de448>2.2.2 :068 > m.eval('y') => 11
binding可以获得当前作用域内部的变量,DSL中经常用到。
最后再说说block,我们经常遇到,就是do.. end
代码接受外部代码块有以下两种:
#命名代码块2.2.2 :001 > def method_c &block2.2.2 :002?> block.call2.2.2 :003?> end => :method_c2.2.2 :004 > method_c { 9 } => 9#匿名代码块2.2.2 :005 > def method_d2.2.2 :006?> yield2.2.2 :007?> end => :method_d2.2.2 :008 > method_d { 10 } => 10
这两种方法的性能如何呢,用ruby内置的Benchmark模块来看下两个的运行时间
我们执行100万次
2.2.2 :012 > require 'benchmark' => false2.2.2 :013 > Benchmark.realtime { 1_000_000.times { method_c { 9 } } } => 0.75586128805298362.2.2 :014 > Benchmark.realtime { 1_000_000.times { method_d { 9 } } } => 0.1121725169941783
这里会发现0.75秒(命名代码块) 第二个0.1秒(匿名代码块)
匿名代码块 效率远远高于命名代码块
所以在开发中我们尽量选择后者
作者:程序员小哥哥
链接:https://www.jianshu.com/p/fea1c8d27087
点击查看更多内容
为 TA 点赞
评论
共同学习,写下你的评论
评论加载中...
作者其他优质文章
正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦