来点技术的:理解下Ruby中的闭包

ruby-lang不知道是不是自己特别的笨的原因,对于这个Closure的概念一直不是很理解,之前一直看大家都渴望Java能支持闭包,自己却不清楚那是个什么,当自己真正的开始学习Ruby的时候才有了点大体的理解,好像很多的动态语言都支持闭包。

当时看过IBM网站上一篇文章闭包的概念、形式与应用,那篇文章作者认为:闭包是函数和引用环境组成的整体,闭包只是在形式和表现上像函数,但实际上不是函数。函数是一些可执行的代码,这些代码在函数被定义后就确定了,不会在执行时发生变化,所以一个函数只有一个实例。闭包在运行时可以有多个实例,不同的引用环境和相同的函数组合可以产生不同的实例。所谓引用环境是指在程序执行中的某个点所有处于活跃状态的约束所组成的集合。其中的约束是指一个变量的名字和其所代表的对象之间的联系。

当时看到这些说法感到一脸茫然,不过在慢慢的理解后就感觉真是那么个事了,我自己感觉是The Ruby Way上的一个例子让我对Ruby中Closure的概念有了比较清楚的理解。

我们可以用下面的代码来将一个字符串数组中的每个字符串反转

words = %w(I am ABitNo Haha)
list = words.map { |x| x.reverse }

下面我们还可以这样做

words = %w(I am ABitNo Haha)
class Symbol
    def to_proc
        Proc.new { |obj, *args| obj.send(self, *args) }
    end
end
list = words.map(&:reverse)

下面的代码似乎变长了,但是这样做还是值得的,不说其他的,至少让我明白了闭包是什么个事。

在 words.map(&:reverse)中,&后面需要一个闭包,但是:reverse只是一个Symbol,所以就会调用刚刚添加到Symbol类中的to_proc方法,然后就得到了这样的代码

list = words.map { |obj, *args| obj.send(self, *args) }

这里的关键就是这个self,如果没有闭包的支持,这个self就是指代的当前调用的对象。但是闭包能够記住创建它的上下文,我们知道当前这个闭包是由:reverse对象通过to_proc方法生成的,这样生成的一个proc記住了自己用到的self就是:reverse,最終第二段代码就与第一段的效果相同了。

当这些都完成后,我们就可以更简洁的来使用其他一些方法了,比如

list = words.map(&:capitalize)

好了,就这些了,都是ABitNo这么一个初级Ruby学习者的个人理解,有什么不对的希望能给指正一下,先谢谢了

TAGS:Ruby

12 COMMENTS >>LEAVE<<

  1. kingheaven

    不是很懂啊~
    好吧~我是ruby白痴.

    Python里应该有类似的东西吧.

  2. ABitNo
    @kingheaven

    python里面肯定会有的吧,其实都差不多的东西了。。。

  3. LAONB

    我看不懂,飘过了。

  4. tmdab123

    快来晃晃

    都没时间看python了

    还是有暑假好 啊

  5. ABitNo
    @tmdab123

    感觉暑假没什么好的。。。除了蚊子多点。。。

  6. ssword

    闭包好玩~ 嘿嘿

    感觉闭包就是个scope的设定,这个scope里可以访问上一个scope中的变量~
    javascript为例,ruby下也差不多啦, 只是ruby匿名函数的关键字貌似是lambda
    function makeCounter(){
    var num=0;
    return function(){
    num+=1;
    return num;
    }
    }

    count=makeCounter();
    alert(count()); //1
    alert(count()); //2

    不过....
    class Symbol
    def to_proc
    Proc.new { |obj, *args| obj.send(self, *args) }
    end
    end
    的这个to_proc是个对Symbol类的扩展,self指向这个Symbol实例本身。send可以用来动态调用方法。博主的代码里貌似没有闭包...

  7. ssword

    闭包好玩~
    不过博主的代码里貌似没见到闭包...

  8. ABitNo
    @ssword

    这个。。。我看出来了,你比我专业很多,我还只是学习阶段哈,都是自己的理解,欢迎高手们指正。。。

    不过我感觉这里面是有闭包的,因为在:reverse要转化成Proc放入下面执行的代码里,就是把

    word.map(&:reverse)
    

    变成了

    words.map { |obj, *args| obj.send(self, *args) }
    

    在这里面,这个obj发出的send方法,里面的self如果没有闭包就应该是这个obj,这个obj在这里是由words做map出来的,但是由于有闭包,所以会记住self产生时的状态,self是在:reverse.to_proc的时候产生的,这里面的self就是个reverse

    不知道我这样理解有没有问题。。。

  9. ssword
    @ABitNo

    以前在the ruby way里貌似见到过words.map(&:captilize)这种写法,当时没想它的实现方法,嘿嘿。

    原先
    words.map{|w| w.reverse}
    换成
    words.map(&:reverse)
    后者明显要好看得多了

    猜一下,&:reverse貌似相当于调用(:reverse).to_proc,返回的呢,貌似就是带一个参数的proc,差不多就相当于

    {|w| w.send(:reverse)}
    

    套上obj.send(self, *args)来看,这里的obj就是w,self就是:reverse,由于reverse方法没有参数,args在这里就忽略了 :)

    ps:博主是山东人?老乡哈 ^_^

  10. ABitNo
    @ssword

    哈哈,我们山东人的老乡真多:lol:

    还没写过什么Ruby的代码,等过了这个暑假再写一下自己对Ruby的理解,现在我感觉还是不太懂,不过我这几天写了相当多的PHP,之前对Ruby不太懂的地方,现在也明白了,看来老师说的话也有对的写上十万行代码就是高手了

  11. swappy

    忒崇拜你了 ,你是大二的学生呀,我这就上大二了,唉………水平差远了,我得努力了。

  12. ABitNo
    @swappy

    哪有什么好崇拜的。。。懂点的人都知道我这叫菜鸟。。。
    你那阿童木工作室还没人呢。。。

LEAVE A RESPONSE >>CANCEL<<

loader