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,并且向do~end块中传入了一个参数,就是yield(one)里的one,这是个“形参”,而另一边one就可以在do~end中使用了,需要用|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)

使用时注意两个地方:
1. 定义方法时,最后一个参数添加“&”符号,表示传入的是方法块对象
2. 传入时也要添加“&”与定义保持一致

如此即可轻松的传递方法(没有js那么灵活)

其实仔细一想,Ruby中的块方法就像是js的回调函数不是吗?闭包不是吗?

一种是匿名的:
直接在方法后面紧跟这代码块do~end表示传入的回调,当然方法中必须要有yield明确调用的地点,参数等

另一种是对象的:
将方法块通过Proc.new赋值给一个变量,然后通过&变量传递到其他的方法中实现回调

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

devilyouwei

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值