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 ...
随机推荐
- TypeScript Class(类)
传统的JavaScript注重用函数和基于原型的继承来创建可复用的组件,但这可能让用习惯面对对象方式的程序员感到棘手,因为他们的继承和创建对象都是由类而来的.从JavaScript的下一个版本,ECM ...
- 使用面向对象对XML进行解析:dom和dom4j的用法
这是一个比较简单的例子,主要是运用面向对象的思想,对XML文件进行解析,用dom和dom4j方法 <?xml version="1.0" encoding="utf ...
- CF721C. Journey
传送门 说实话,这是一道非常简单的DP题,简单到如果放到NOIp第二题可能都有些差强人意,然而我写崩了. 所以简单记录一下. 需要注意的是,这道题的DP应该是从$N$点开始,以1为边界,满足最短路的三 ...
- 【原】react中如何使用jquery插件
react的思想是虚拟dom,提倡最好较少dom的操作,可是我们在写网页的时候,有些复杂的交互还是离不开jquery插件的.而且当你把jquery直接拿来用的时候,你会发觉会报错,要么是找不到那个插件 ...
- mysql使用索引优化查询效率
索引的概念 索引是一种特殊的文件(InnoDB数据表上的索引是表空间的一个组成部分),它们包含着对数据表里所有记录的引用指针.更通俗的说,数据库索引好比是一本书前面的目录,能加快数据库的查询速度.在没 ...
- unix-ln 命令
指令名称 : ln 使用权限 :所有使用者 使用方式 : ln [options] source dist, 其中 option 的格式为 : [-bdfinsvF] [-S backup-suffi ...
- JSP传统标签开发
1.标签技术的API类继承关系 1).JspTag接口是所有自定义标签的父接口 该接口中没有任何属性和方法,只有两个直接子接口,Tag接口和SimpleTag接口,把实现Tag接口的自定义标签叫做传统 ...
- JavaScript学习笔记——节点
javascript-节点属性详解 根据 DOM,HTML 文档中的每个成分都是一个节点. DOM 是这样规定的: 整个文档是一个文档节点 每个 HTML 标签是一个元素节点 包含在 HTML 元素中 ...
- 未能加载文件或程序集“MySQLDriverCS
未能加载文件或程序集“MySQLDriverCS, Version=3.0.1735.36021, Culture=neutral, PublicKeyToken=172f94dfb0faf263”或 ...
- 负margin小记
static元素 margin-top/left负值,元素向指定方向移动, margin-bottom/right负值,元素不动,后续元素前移 float元素 左浮, ...