Ruby中有意思的块
块:是在调用方法时,能与参数一起传递的多个处理的集合
简单点说,跟在方法执行后面的do |变量| end就是一个块,这个块会被传入方法中去执行!
这个非常厉害,非常有意思!
在ruby中,如果需要便利一个数组,因为Ruby中一切皆是对象,可以使用Array类自身的each方法。
例如遍历:
a = [1,2,3,4,5,6]
只需要使用
a.each do |one|
p one
end
这里用到就是ruby已经定义好的一个块,那么如何自己弄一个这样的块(自定义)?
自定义带块的方法
需要用到一个关键词 yield
需要了解这个,我们就先写一个each方法出来!如下:
#为array类添加一个方法myeach
class Array
def myeach
for one in self
#重要的一步
yield(one)
end
end
end
a = [1,2,3,4,5,6]
#测试myeach,就像原来自带的each一样了
a.myeach do |one|
puts one
en
注意到,上面自定义部分其实只有三行代码,利用了一个循环(不带块的那种原始方法),遍历的是self,也就是对象本身,中间是“yield”关键词,这很关键!
你可以这样理解do |one| ~ end部分其实是临时定义了一个匿名方法,并且这个方法被嵌入到了myeach当中,也就是块紧跟着的方法。嵌入的地方就是yield,它替换了yield,并且向doend块中传入了一个参数,就是yield(one)里的one,这是个“形参”,而另一边one就可以在doend中使用了,需要用|one|来接收,这里的one可以改成别的变量,这是个“实参”!
这就像你在方法中突然嵌入了一个方法,执行了一些代码块一样,只不过,“块”要比方法中调用别的方法强大,灵活多了,各个对象可以根据自己情况来调用方法,传入不一样的值,另外do~end中间的相当于一个临时方法或者有点像闭包(匿名函数),这就使得传入的方法块变的也非常的灵活了,可以临时定义,修改,做出五花八门的功能实现,所以最终被替换的yield也是不确定的,myeach不知道自己将会面临怎样的一个代码块。很有意思
不定带块情况
有的时候,开发者可能传入块,可能不传入,这样需要做判断,使用:block_given?
class Array
def myeach
#如下改进,判断是否传入了块
if block_given?
#传入了就要嵌入这个块里的代码,并且向块中传递一个one变量
for one in self
yield(one)
end
else
for one in self
p one
end
end
end
end
a = [1,2,3,4,5,6]
a.myeach
puts
a.myeach do |one|
puts one*2
en
区别:
第一种没有块的,就使用myeach默认的实现
第二种,如果指定了块,就是用块里的方法去做
带多个参数的块方法
def block_args_test
yield()
yield(1)
yield(1,2,3)
end
block_args_test do |a|
p [a]
end
block_args_test do |a,b,c|
p [a,b,c]
end
block_args_test do |*a|
p [a]
en
在block_args_test当中将会调用三次块中的代码
第一次不传参数,第二次传入一个1,第三次是1,2,3三个参数
然后看看要用参数的代码块
第一个就只用一个,如果传入0个参数,则会显示一个nil,以后无论多少个参数都是使用第一个
第二个同理
第三个就将接受到的参数转换为一个数组,这与ruby定义方法时接受可变参数情况相似!
Ruby的块方法与JS的方法变量
写过js的朋友知道,js中function可以作为对象,即将function赋值给一个变量,然后使用变量来调用方法,因为变量是可以传递的,所以就使得我们可以轻松的在js中传递方法!
Ruby不可以传递一个def的方法,但是可以使用block来实现,也就是块方法
上面所介绍的都是紧跟在方法后面的“匿名块方法”,也就是传入一次后,等到执行结束就不用了,如果我们要在多个方法中调用同一个块方法,就需要用到块方法的对象!(像js一样传递对象变量)
块方法赋值给对象,简单的例子:
show = Proc.new do |res|
p res
end
Proc能让块变成对象!
这里使用Proc.new将紧跟其后的代码块交给了变量show
这相当于js的:
show = function(res){
console.log(res);
}
调用他使用call:
show.call("hello world")
和前面的一样,将他传入其他方法中!
show = Proc.new do |res|
p res
end
def plus(a,b,&block)
block.call(a+b)
end
plus(1,5,&show)
使用时注意两个地方:
- 定义方法时,最后一个参数添加“&”符号,表示传入的是方法块对象
- 传入时也要添加“&”与定义保持一致
如此即可轻松的传递方法(没有js那么灵活)
其实仔细一想,Ruby中的块方法就像是js的回调函数不是吗?闭包不是吗?
一种是匿名的:
直接在方法后面紧跟这代码块do~end表示传入的回调,当然方法中必须要有yield明确调用的地点,参数等
另一种是对象的:
将方法块通过Proc.new赋值给一个变量,然后通过&变量传递到其他的方法中实现回调
Ruby中有意思的块的更多相关文章
- Ruby学习之代码块
代码块在其他的语言中都或多或少接触过一些,如perl中sort{$a<=>$b}keys,传入代码块实现按数值排序,在swift中用到闭包,更加深入学习到training closure. ...
- Ruby 中的闭包-代码块
看了一片文章https://ruby-china.org/topics/38385讲closure的. 写下一些感想: 闭包就是 一个函数能够记住和存取它的lexical作用域,即使这个函数是在它的l ...
- 一个简单的ruby生成器例子(用连续体Continuation实现)
ruby中有很多经典的驱动器结构,比如枚举器和生成器等.这次简单介绍下生成器的概念.生成器是按照功能要求,一次产生一个对象,或称之为生成一个对象的方法.ruby中的连续体正好可以用来完成生成器的功能. ...
- Java转Ruby【快速入门】
最近参加实习了,公司的技术栈中需要用到 Ruby 以及 Rails 框架,所以算是开始了踩坑之旅吧.. Ruby 简介 网上的简介要搜都能搜到,具体涉及的包括历史啦之类这里不再赘述,提几个关键词吧: ...
- 3-18/19 (自我练习)30多个《Ruby元编程》的spell(pattern)小例子。
Spell,也称pattern,idiom # Around Alias:从一个重新定义的方法中调用原始的,被重命名的版本. # old_reverse是未改变的原始方法,reverse/new_re ...
- 浅谈ruby中的block及yield
今天写代码的时候遇到了block_given?,查阅了一下语法书中并没有相关的知识点,于是翻阅微博及结合工作中的实际代码,整理如下: 一.“块”: ruby的块指的是什么? 是 do~end中间的那部 ...
- ruby中的instance_eval,class_eval,eval
ruby具有在运行时执行以字符串形式保存的代码的功能设施,eval族方法 .包括Kernel#eval,Object#instance_eval,Module#class_eval. Kernel#e ...
- ruby中的可调用对象--方法
上一篇讲了ruby中的可调用对象proc和lambda,他们都是块转换成的对象.ruby中的可调用对象还有方法.通过使用method方法,并且以方法名作为参数(字符串或者符号),就可以得到一个方法对象 ...
- Linux 在 i 节点表中的磁盘地址表中,若一个文件的长度是从磁盘地址表的第 1 块到第 11 块 解析?
面试题: 在 i 节点表中的磁盘地址表中,若一个文件的长度是从磁盘地址表的第 1 块到第 11块,则该文件共占有 B 块号.A 256 B 266 C 11 D 256×10 linux文件系统是L ...
随机推荐
- 从 Spring 2.5 开始就可以使用注解来配置依赖注入,而不是采用 XML 来描述一个 bean。
1.在 XML 注入之前进行注解注入,因此后者可以被前者重写. 2.在默认情况下注解在 Spring 容器中不打开,需要配置启动. <beans xmlns="http://www.s ...
- R处理大数据集
R会把所有的对象读存入虚拟内存中.对我们大多数用户来说,这种设计可以提高与R相互的速度,但是当分析大数据集时,这种设计会降低程序运行速度有时还会产生跟内存相关的错误. 内存限制主要取决于R的build ...
- dfs 无向图两节点间的所有路径
标题:风险度量 X星系的的防卫体系包含 n 个空间站.这 n 个空间站间有 m 条通信链路,构成通信网.两个空间站间可能直接通信,也可能通过其它空间站中转. 对于两个站点x和y (x != y), 如 ...
- POJ 2182 解题报告
Lost Cows Time Limit: 1000 MS Memory Limit: 65536 KB Description N (2 <= N <= 8,000) cows have ...
- UWP--数据绑定的几种方式
1.后台代码: 2.后台定义属性,前台XAML 中绑定: 3.XAML 中定义资源并应用(资源中自定义对象): 4.用元素值绑定:
- dreamweaver中的 map怎么调用?_制作热点图像区域
我们浏览网页时,经常看到一些图片上会出现特别的超链接,即在一张图片上有多个局部区域和不同的网页链接,比如地图链接. 这就是映射图像(Image Map),它是指一幅根据链接对象不同而被人为划分为若干指 ...
- jQuery kxbdMarquee 无缝滚动
转:http://code.ciaoca.com/jquery/kxbdmarquee/ <marquee> 曾是 IE 下独有的一个走马灯效果的标签,其他浏览器并不兼容,于是出现了使用 ...
- Babel指南——基本环境搭建
ECMAScript的现状 ECMAScript,本身是一个脚本语言的设计规范,基于此规范,有许多为人熟知的语言,如JavaScript.ActionScript等.而时至几年前,随着Node.js的 ...
- MySQL基础入门-第一课 新建数据库(linux版本)
MySQL linux 登录MySQL sudo ),name ),phone ) ); # 或者 ),name ),phone )); 数据类型 数据类型 大小(字节) 用途 格式 INT ...
- eclipse如何安装插件
eclipse安装插件以springsource-tool-suite为例 打开eclipse,找到help/About Eclipse/ 然后点击右下角图标 找到EclipsePlatform对应的 ...