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 ...
随机推荐
- 加州大学伯克利分校Stat2.2x Probability 概率初步学习笔记: Section 3 The law of averages, and expected values
Stat2.2x Probability(概率)课程由加州大学伯克利分校(University of California, Berkeley)于2014年在edX平台讲授. PDF笔记下载(Acad ...
- 我所了解的meta
https://github.com/hoosin/mobile-web-favorites 总况 meta 标签分两大部分:HTTP 标题信息(http-equiv)和页面描述信息(name). h ...
- BZOJ1588[HNOI2002]营业额统计
传送门 平衡树常规题,给出两种实现算法 Treap版: //OJ 1610 //by Cydiater //2016.9.1 #include <iostream> #include &l ...
- 【原】dangerouslySetInnerHTML, 让React正常显示你的html代码
昨天在弄一个让内容换行显示时,遇到一个问题,就是我有<br />的代码在页面中不换行,而是直接显示<br />,代码如下: <!DOCTYPE html> < ...
- 关键词提取1-C#
C# 中文分词算法(实现从文章中提取关键字算法) using System;using System.IO;using System.Text;using System.Collections;usi ...
- JavaWeb学习笔记——JDOM
JavaDOC的网址:http://www.jdom.org/docs/apidocs/index.html import java.io.FileOutputStream; import org.j ...
- JavaScript学习笔记——变量和数据类型
一.javascript命名规范 1. 严格区分大小写 2. 变量的命名必须以字母或 _或 $开头,余下的部分可以是任意的字母,数字,或者是 _或者是$ 3.不能用关键字或者是保留字命名. 4.jav ...
- win7或win2008 R2 被远程登录日志记录 系统日志
事件查看器 → Windows 日志 → 安全 (win7 事件查看器 打开方式 :计算机 右键 → 管理 → 计算机管理 → 系统工具 → 事件查看器 windows server 2008 ...
- Tips for writing a paper
Tips for writing a paper 1. Tips for Paper Writing 2.• Before you write a paper • When you are writi ...
- UVa 11988 Broken Keyboard(链表->数组实现)
/*数组形式描述链表:链表不一定要用指针. 题目链接:UVa 11988 Broken Keyboard 题目大意: 小明没有开屏幕输入一个字符串,电脑键盘出现了问题会不定时的录入 home end ...