Ruby中Block, Proc, 和Lambda
Block
Blocks就是存放一些可以被执行的代码的块,通常用do...end 或者 {}表示
例如:
[1, 2, 3].each do |num|
puts num
end [1, 2, 3].each { |num| puts num }
Blocks可以和.each、.times等联合使用,用来对每一个元素执行一段指令。
还有很多非常有用的方法需要用到Blocks,例如 collect
collect方法可把数组中的每个元素都传给Blocks, 在Blocks中可对数组元素进行操作
例如:
my_nums = [1, 2, 3]
my_nums.collect! { |num| num ** 2 }
下面我们来想一下,为什么有些方法允许使用Blocks而有些不是
因为允许使用Blocks的methods有办法从调用方法把控制权转移到Blocks然后再转移回来到调用方法处。我们可以通过yield关键字来实现。
def block_test
puts "We're in the method!"
puts "Yielding to the block..."
yield
puts "We're back in the method!"
end block_test { puts ">>> We're in the block!" }
--------------------------------------------------------------------
输出运行结果:
We're in the method!
Yielding to the block...
>>> We're in the block!
We're back in the method!
nil
从上段程序可以看出, 当我们调用block_test时, 先进入block_test程序,然后运行, 当程序走到了yield处, 程序的控制权同过yield转移到了block中(即块
{puts ">>> We're in the block!"}), block执行完毕后, 再把程序控制权还给block_test方法, 程序从yield关键字后继续运行。
我们还可以给yield传参数
def yield_name(name)
puts "In the method! Let's yield."
yield("Kim")
puts "In between the yields!"
yield(name)
puts "Block complete! Back in the method."
end yield_name("Eric") { |n| puts "My name is #{n}." } # Now call the method with your name!
yield_name("Wei") { |n| puts "My name is #{n}"}
-----------------------------------------------------------------
输出:
In the method! Let's yield.
My name is Kim.
In between the yields!
My name is Eric.
Block complete! Back in the method.
In the method! Let's yield.
My name is Kim
In between the yields!
My name is Wei
Block complete! Back in the method.
nil
分析此段代码:
1.我们定义了带有一个参数name的yield_name方法
2.在程序第9行,我们调用了yield_name方法并传入了参数"Eric", 因为yield_name包含yield语句,所以我们要提供一个block块
3.在yield_name中,我们传给了yield一个参数"Kim", 在block块中n现在存放的就是"Kim", 所以我们输出的是"My name is kim"
4.程序回到yield_name中, 下面有把yield_name的参数name(name中存放的是"Eric")传给了yield,所以我们输出"My name is Eric"
Proc
我们说过, 在Ruby中所用的一切都是对象, 这其实并非事实, 因为blocks不是对象。因此blocks不能被保存到变量, 并且不具备变量所拥有的任何能力。因此我们需要proc。
你可以认为一个proc存储一个block。 就像你可以把一段代码放在一个方法中一样, 你也可以把一个有名字的block放进proc中。proc是保证你代码的DRY(don't repeat yourself)的非常好的方式。如果使用block你必须在每次你要用到它的地方重新写一遍, 但是使用proc你的代码只要写一次就可以多次使用它。
proc的定义非常简单。 你仅仅需要调用Proc.new(Proc首字母大写), 然后传入一个你想要保存的block就可以了
例如:
floats = [1.2, 3.45, 0.91, 7.727, 11.42, 482.911]
round_down = Proc.new { |n| n = n.floor }
ints = floats.collect(&round_down)
我们可以传递proc给一个需要block的方法,我们不必一遍遍重写这个block。&用来把proc转换为block(因为.collect!和.map!通常需要使用block).
使用proc的好处:
1.proc是成熟的对象, 因此它具有一般对象所拥有的一切能力,而block不是对象。
2.不同于block,proc能被一次次使用而不用需要重写。
group_1 = [4.1, 5.5, 3.2, 3.3, 6.1, 3.9, 4.7]
group_2 = [7.0, 3.8, 6.2, 6.1, 4.4, 4.9, 3.0]
group_3 = [5.5, 5.1, 3.9, 4.3, 4.9, 3.2, 3.2] over_4_feet = Proc.new {|x| x >= 4} can_ride_1 = group_1.select(&over_4_feet)
can_ride_2 = group_2.select(&over_4_feet)
can_ride_3 = group_3.select(&over_4_feet)
我们还可以直接使用.call来调用proc
例如:
hi = Proc.new{ puts "Hello!" }
hi.call
------------------------------------------
输出
Hello!
当symbol遇到proc
我们同样也能用&把symbol转换为proc
strings = ["", "", ""]
nums = strings.map(&:to_i)
# ==> [1, 2, 3]
lambda
和proc一样,lambda也是对象。 除了一些语法上的差异和一些行为上的特性, lambda和proc是一样的。
写法: lambda {puts "Hello"} 和 Proc.new {puts "Hello"}
lambda的语法: lambda{ |para| block }
lambda在proc可以使用的地方一样有用。
strings = ["leonardo", "donatello", "raphael", "michaelangelo"]
symbolize = lambda { |para| para.to_sym }
symbols = strings.collect(&symbolize)
--------------------------------------------------------------------
输出 [:leonardo, :donatello, :raphael, :michaelangelo]
上面代码中 lambda 有一个参数, 并且对这个参数使用.sym方法把字符串转换为symbol。 &用来把lambda转换成block。
lambda vs proc
如果你感觉proc和lambda非常相似, 这是因为他们确实非常相似。。。
它们只有两个主要区别:
1.lamba检查传进来参数的数量,而proc不用。这意味着当你传进错误数量的参数时lambda将会抛出错误,而proc将会忽略不被期望使用的参数,并把它们赋值为nil。
2.当lambda返回时, 它把控制权转移给方法, 而当proc返回时, 它直接返回而不回到调用方法。
例如:
def batman_ironman_proc
victor = Proc.new { return "Batman will win!" }
victor.call
"Iron Man will win!"
end puts batman_ironman_proc
--------------------------------------------------------------
输出
Batman will win!
nil
def batman_ironman_lambda
victor = lambda { return "Batman will win!" }
victor.call
"Iron Man will win!"
end puts batman_ironman_lambda
----------------------------------------------------------
输出:
Batman will win!
Iron Man will win!
nil
Ruby中Block, Proc, 和Lambda的更多相关文章
- ruby中Block, Proc 和 Lambda 浅析
Block 与Proc的区别: Block是代码块,Proc是对象: 参数列表中最多只能有一个Block, 但是可以有多个Proc或Lambda; Block可以看成是Proc的一个类实例. Proc ...
- ruby中的可调用对象--proc和lamdba
ruby中将块转变成对象的三种方法 ruby中的大部分东西都是对象,但是块不是.那么,如果你想存下来一个块,方便以后使用,你就需要一个对象.ruby中有三种方法,把块转换成可以利用的对象. Proc. ...
- Ruby中的语句中断和返回
李哲 - APRIL 28, 2015 return,break,next 这几个关键字的使用都涉及到跳出作用域的问题,而他们的不同 则在于不同的关键字跳出去的目的作用域的不同,因为有代码块则导致有一 ...
- ruby中proc和lambda的return区别
学习ruby有一段时间了,但是我看了好几遍proc和lambda的return区别的区别讲解,始终没明白到底什么区别,今天上午又看,终于感觉是茅塞顿开有点领悟了 一下内容部分来自<<rub ...
- [翻译]理解Ruby中的blocks,Procs和lambda
原文出处:Understanding Ruby Blocks, Procs and Lambdas blocks,Procs和lambda(在编程领域被称为闭包)是Ruby中很强大的特性,也是最容易引 ...
- Ruby Proc 和 lambda的共同点和区别
Proc 和 lambda 的目的是把block {....} 变成类似方法一样的对象,使其不需要重复编写同样的block. Proc 和 lambda 的共同点: 语法类似Proc.new{|n| ...
- 理解Ruby中的作用域
作用域对于Ruby以及其它编程语言都是一个需要理解的至关重要的基础知识.在我刚开始学习ruby的时候遇到很多诸如变量未定义.变量没有正确赋值之类的问题,归根结底是因为自己对于ruby作用域的了解不够, ...
- ruby中的可调用对象--方法
上一篇讲了ruby中的可调用对象proc和lambda,他们都是块转换成的对象.ruby中的可调用对象还有方法.通过使用method方法,并且以方法名作为参数(字符串或者符号),就可以得到一个方法对象 ...
- Ruby 中的闭包-代码块
看了一片文章https://ruby-china.org/topics/38385讲closure的. 写下一些感想: 闭包就是 一个函数能够记住和存取它的lexical作用域,即使这个函数是在它的l ...
随机推荐
- iOS “智慧气象”APP中用到的第三方框架汇总
“智慧气象”是我最近在公司接手的项目,已经完成最新版本的更新并上架,在此分享下其中用到的第三方框架的使用. 应用地址:APP商店搜索“智慧气象” MJRefresh(下拉刷新)业界知名下拉刷新框架就不 ...
- 树链剖分I 原理
树链剖分(Heavy Light Decomposition, HLD)是一种将对[树上两点间的路径]上[边或点]的[修改与查询]转化到[序列]上来处理的方法. 目的:将树的边或点转化到一个线性结构( ...
- STL之vector
参考资料: 1.codeproject 2.csdn 3.cplusplus
- 获取URL的code的参数的值
1.获取URL的code的参数的值 需求说明:现在有URL为http://www.bdqn.cn/index.php?code=sdR4,请使用字符串对象的属性和方法来获取code的值,并把其指都转化 ...
- Beta版本冲刺第二天 12.6
一.站立式会议照片: 二.项目燃尽图: 三.项目进展: 成 员 昨天完成任务 今天完成任务 第三天冲刺要做任务 问题困难 心得体会 胡泽善 完成了"记住密码"的的逻辑以及BUG修改 ...
- javascript表单验证
表单HTML <form action="" method="post"> <fieldset class="login" ...
- Yocto开发笔记之《网卡配置》(QQ交流群:519230208)
QQ群:519230208,为避免广告骚扰,申请时请注明 “开发者” 字样 ============================================== # ifconfig -a # ...
- NSXMLParser解析本地.xml数据(由于like7xiaoben写的太好了,我从她那里粘贴过来的)
NSXMLParser解析简要说明 .是sax方法解析 .需要创建NSXMLParser实例 (alloc) 并创建解析器 (initWithData:) 为解析器定义委托 (setDelegate: ...
- Sublime Text 3 快捷键整理
选择类Ctrl+D 选中光标所占的文本,继续操作则会选中下一个相同的文本.Alt+F3 选中文本按下快捷键,即可一次性选择全部的相同文本进行同时编辑.Ctrl+L 选中整行,继续操作则继续选择下一行, ...
- glade2支持C++代码的输出(2)
今天更新了一个BaseObject的代码:BaseObject.002.zip 同时将glade2生成C++代码的代码进行了调整,基于2.12.2的补丁为:cpp_out_2.patch.tar.xz ...