前情提要:

第11天开始,要更深入Ruby的精髓!

Ruby经典面试题目#11
Ruby的block,proc,lamdba方法比较?What’s difference between blocks,procs and lambdas?

block代码内存块

代码内存块是用do…end围起来,围出特定一个区域、放代码的地方。
就好像跑马拉松一样,道路上会进行交通管制,把参赛者的跑道围起来。

do…end的形式常常使用在数组和循环里,把数组想成参赛者的列表,循环想成跑道,每个参赛者(数组内的元素)都要一个一个进入跑道(循环),是不是就很好理解了呢?

block: do…end

我们来用do…end围出block。昨天提到ruby invoke method的阶层有五层:

find_method = [“Class”,“Module”,“Object”,“Kernel”,“BasicObject”]

find_method.each do |find_method|
p find_method
end
结果显示为:

Class
Module
Object
Kernel
BasicObject
block: {}

假如某个特定参赛者选手如我,每年都一次马拉松,而2018年即将跑第3次啦!我可以用大括号{}印出如下:

3.times {p“I love running 42K marathon!”}
因为很重要所以喊3次,这个大括号{}围出的内存块,忠实地印出(chao-ok-huangdaoyi):

“I love running 42K marathon!”
“I love running 42K marathon!”
“I love running 42K marathon!”
有没有注意到,不管是do…end,还是{},前面都跟着method呢?
do…end前有.each这个Array里的方法;{}前有.times这个属于Integer的方法。

所以,重点出现:block不是物件!必须跟在其他的方法或物件之后。

3.times {p“block is not Object!!!“} #很重要所以说3次
block: yield

人生就像马拉松一样漫漫长路。有的时候跑步跑累了,我们需要喝点水、休息喘口气。那该如何用block表示呢?我们使用yield方法呼叫:

def keep_running
p“-start line-”
yield #block
p“-finish line-”
end

keep_running {
p“drink water”
}
结果显示为:

-start line-
drink water
-finish line-
在ruby on rails项目里,我们也很常在erb档名下,发现这种利用yield方法,调用代码内存块的页面:

<!DOCTYPE html>
<html>
<head>
<meta http-equiv=“Content-Type”content=“text/html;charset=utf-8”/>
</head>

<body>
<%= yield %>
</body>
</html>
其中<%= yield %>就是在html页面代入ruby代码的内存块。关于更多yield说明,可以参考Ruby on Rails Guide.

Proc程序物件

Proc是程序物件,跟block一样可放入程序内存块。

在Ruby API里,定义:

Proc objects are blocks of code that have been bound to a set of local variables.
方刚我说明到block不是物件,因此如果我们遇到需要一次处理很多的block,或是多次使用一个block的情况时,与其重复写code,不如把需要重复的部分写成物件。

我现在想进一步利用Proc放入程序判断,计算在马拉松赛事、半马和全马分别跑过几公里。

首先用block列出参赛纪录:

place = [“2012太鲁阁半马”,“2012玉山半马”,“2013万金石半马”,“2013双溪半马”,“2013台北市半马”,“2014黄金海岸半马”,“2014 Perth半马”,“2016 Sydney全马”,“2017 Melbourne全马”,“2018大堡礁全马”]

place.each do |place|
puts place
end
block显示出,凡跑过必留下痕迹!

2012太鲁阁半马
2012玉山半马
2013万金石半马
2013双溪半马
2013台北市半马
2014黄金海岸半马
2014 Perth半马
2016 Sydney全马
2017 Melbourne全马
2018大堡礁全马
以上纪录显示,从2012-2018年,半马(21KM)跑过7次,全马(42K)跑3次。由于block无法代入参数,此时Proc就派上用场了!

Proc的类别方法

来写我人生第一个使用Proc物件的跑步方法proc_running。
在这个类别方法(class method)内,用.new产生新的程序物件。
在方法之外,用{}大括号围出block,用.call方法呼叫程序物件proc本身:

def proc_running
Proc.new
end
proc = proc_running {“I love running!”}
p proc.call #=>“I love running”
来看看Proc代入参数之后,可以做的事就变多啰,我现在想计算半马(21KM)跑过7次,全马(42K)跑3次,分别是几公里:

def count_km(km)
return Proc.new {|n| n*km}
end

full_marathon = count_km(42)#126
half_marathon = count_km(21)#147

p“I've run #{half_marathon.call(7)} Km in Half Marathon and #{full_marathon.call(3)} Km in Marathon”
还记得#{}可以帮我们插入字串吗?(此方法会先利用to_s将传入的Integer成String格式)
所以计算答案揭晓:

“I've run 147 Km in Half Marathon and 126 Km in Marathon”
Proc的实体方法

Proc可以new出新的程序物件实体km_proc:

km_proc = Proc.new { |km,*n| n.collect { |n| n*km } }
p km_proc.call(42,1,3)#=> [42,126]
p km_proc.call(21,1,7)#=> [21,147]
这样我就可以把计算的跑步公里数,美美地用.collect这个数组方法裱框印出来!

[42,126]
[21,147]
观察刚刚的类别方法,我们发现Proc可以代入参数,也可以用return回传参数,那我想要仿造文章前头这段block代码概念:

def keep_running
p“-start line-”
yield #block
p“-finish line-”
end

keep_running {
p“drink water”
}
写一个喝水Proc程序:

def proc_keep_running
p“-start line-”
water_proc = Proc.new { return“drink water”}
water_proc.call
p“-finish line-”
end
p proc_keep_running
# Prints“-start line-”but not“-finish line-”
结果印出:

-start line-
drink water

疑?怎么喝完水就打住,不继续跑向终点-finish line-呢?
我们发现了:

在proc内使用return会立即返回,不再继续执行后面程序。
(所以,永远不能在Proc内使用return,这样跑马拉松会无法抵达终点啊啊啊啊!)

lambda匿名函数

身为工程师,问题代表着机会;出现问题就代表会有解决方案的出现,在Proc中有一个特别的用法叫lambda。创建方法有两种指令:lambda or ->()

lambda_running = lambda { puts“Run with lambda!”}
lambda_running = -> { puts“Run with lambda!”}
如果我们使用puts印出,会发现lambda是Proc的一种:

p lambda_running
#<Proc:0x000056043ddfd1e8@main.rb:11(lambda)>
我们来用基本的程序语法,比较proc与lambda回传值:

刚刚说到Proc方法内不能放return,

def proc_run
proc = Proc.new { return }
proc.call
p“Run with Proc!”
end
proc_run #跑不出来“Run with Proc”结果!
但lambda可以:

def lambda_run
lam = -> { return }
lam.call
p“Run with lambda!”
end

lambda_run #=>“Run with lambda!”
从下文说明,我们可以了解Proc只会回传目前阶层的内容,而不会像一般的方法以及lambda匿名方法一样,整个走完方法里面的该回传的值。

The difference between procs and lambdas is how they react to a return statement.A lambda will return normally,like a regular method.But a proc will try to return from the current context.The reason is that you can’t return from the top-level context.出处
现在来用lambda的两种调用写法lambda or ->()练习写作代码,分别回传半程马拉松(hm)和全程马拉松(fm)的公里数(leafor):

half_proc = lambda {|hm,fm| hm}
full_proc = ->(hm,fm){fm}
p half_proc.call(21,42)#21
p full_proc.call(21,42)#42
结果half_proc.call会回传21,full_proc.call会回传42。

如果参数多放一个呢?1.5个马拉松

p full_proc.call(21,42,63)
会出现错误讯息:

main.rb:17:in `block in <main>':wrong number of arguments(given 3,expected 2)(ArgumentError)
这个原因在于:

lambda是方法,所以它会检查参数个数是否匹配。
来用程序举例一下:

lambda_argument = lambda {|x| x*2}
p“Lambda result: 21Km *2= #{lambda_argument.call(21)}Km”

proc_argument = Proc.new {|x,y|“I don't care how many arguments inside Proc!”}
p“Proc result: #{proc_argument.call(21,42,63)}”
结果印出:

“Lambda result: 21Km *2= 42Km”

“Proc result: I don't care how many arguments inside Proc!”
超级比一比的表格又出现了:

block程序内存块Proc程序内存块物件lambda匿名方法
不是物件带名字的内存块物件,可储存变数和Proc类似,但更加接近method方法
不是参数可带参数严格检查参数数目
N/A在Proc里return其他值,会离开此物件的方法在lamba里return其他值,会回来继续执行完方法
最后的最后,我们用lambda来写马拉松喝水的方法吧!

def lambda_keep_running
p“-start line-”
water_lambda = lambda { return“drink water”}
p water_lambda.call
p“-finish line-”
end
lambda_keep_running
结果印出:

-start line-
drink water
-finish line-
顺利迎向终点finish line了!

也祝大家都能顺利完赛!!!:)

转载于:https://www.cnblogs.com/lannyQ-Q/p/10804659.html

Day11 - Ruby的block,proc,lamdba方法比较相关推荐

  1. Ruby 之 Block, Proc, Lambda 联系--区别,转载

    Ruby 之 Block, Proc, Lambda Block Block 不是对象,是Ruby的语言特性,近似于闭包(Closure). 范例: def meth    res=  yield   ...

  2. iOS之深入解析如何使用Block实现委托方法

    一.前言 Block 和 Delegate 是对象间传递消息的常用机制,这两个机制可以说是各有千秋. Delegate 可以很方便把目标动作的执行过程划分为多个方法,以展现不同时间节点下特定的操作:B ...

  3. Ubuntu开机出现“error: invalid environment block“的解决方法

    Ubuntu开机出现"error: invalid environment block"的解决方法 1. 错误状态 2. 解决办法 1. 错误状态 当使用GRUB启动ubuntu时 ...

  4. yum安装ruby_CentOS 7下配置Ruby语言开发环境的方法教程

    本文跟大家分享的是在CentOS 7下配置Ruby语言开发环境的方法教程,分享出来供大家参考学习,下面来看看详细的介绍: 安装Ruby 2.2 CentOS7存储库中的Ruby版本为2.0,但如果需要 ...

  5. 微信小程序手机号解密报错:pad block corrupted 解决方法

    微信小程序手机号解密报错:pad block corrupted 解决方法 微信小程序获取用户手机号,后端解密手机号的时候偶尔会报错 javax.crypto.BadPaddingException: ...

  6. ruby语法_Ruby函数(方法)语法

    ruby语法 The Ruby language makes it easy to create functions. Ruby语言使创建函数变得容易. Function Syntax 功能语法 de ...

  7. Vivado System Generator for DSP - “Error evaluating ‘OpenFcn‘ callback of Xilinx Block“错误解决方法

    使用Vivado System Generator for DSP时,遇到"Error evaluating 'OpenFcn' callback of Xilinx Block" ...

  8. 用pry阅读ruby源码--以task方法为例

    rails项目中有个目录 lib/tasks,里面定义了一个rake任务: task hello: :hello do puts "hello" end 看到这里的时候,是不是可能 ...

  9. 微信小程序解密encryptedData报错:pad block corrupted 解决方法

    今天碰到一个pad block corrupted错误,跟代码发现是Cipher里面的doFinal()爆出的错. 代码: public static JSONObject getUserInfo(S ...

最新文章

  1. 基于 HTML5 WebGL 的 3D 棉花加工监控系统
  2. 关于JQ的点击事件在微信手机端无响应的解决方案
  3. allowedExts php,通过php扩展增加一个内置函数
  4. 语音识别热词_出门问问 TWS 耳机语音交互解决方案
  5. AtomicInteger 的使用
  6. 《Pro ASP.NET MVC 3 Framework》学习笔记之一【MVC的历程,优点,HelloWorld】
  7. ubuntu使用git时,终端不显示git分支。
  8. 分类 Classification
  9. 【云分析】之一《公有云对企业发展战略的影响》
  10. 18年12月英语六级第二套听力单词
  11. AWSome Day 2019 线上云技术课堂(2)
  12. 高等数学——变限积分求导
  13. [经]信用体系,金融改革
  14. java 函数 throw_java为什么有些异常throw出去需要在函数头用throws声明,一些就不用。...
  15. 新买的电脑硬盘如何分区
  16. 高数--函数--初等函数
  17. 第一代真空电子管计算机主要应用范围是,计算机应用基础知识课件.ppt
  18. 【树莓派】树莓派SD卡测速一键脚本,SD卡读写速度测试程序
  19. 网页使用思源字体 CSS
  20. 多径效应(multipatheffect)

热门文章

  1. java没有编译器吗_java有编译器吗
  2. 艺赛旗开发技巧-根据文本点击网页元素
  3. 【poj 3069】萨鲁曼的大军
  4. 【亲测有效】解决执行nrm ls命令查看不到*星号的问题
  5. [转]ESMTP的三个认证方式: CRAM-MD5 PLAIN和LOGIN
  6. 2015最新经典语句搞笑段子
  7. Workspace Cannot Be Created
  8. Mac OS X: MS Office 2008 Preference Manifests
  9. 虚拟机无法启用 虚拟化引擎 Inter VT-x/EPT,mumu模拟器报错Hyper-v 开启,无法启动模拟器
  10. QCC305x系列开发教程(入门篇)之1.2-安装开发中需要配套软件