zoukankan      html  css  js  c++  java
  • ruby中的&操作符,以及各种闭包、proc的调用研究

     
    class Array
      def iterate!(&code) #注意这里用了&符号
        self.each_with_index do |n,i|
          self[i] = code.call(n)
        end
      end
    end
    
    arr = [1,2,3,4]
    
    arr.iterate! do |n|
      n ** 2
    end
     
    #[1, 4, 9, 16]
    

      

    今天读代码的时候,被这个&符号给蒙住了。ruby语言中时不时蹦出各种奇怪的符号,而且作用不明。还不好查得。

    于是认真研究了一下。

    &操作符的真正含义:proc对象和块之间的切换符号。&code 这是一个块, code 这是一个proc对象。简单的去掉&操作符,我们就能再次得到一个Proc对象。

    ===================================================

    呃,其实如果没有上下文,完全说不清楚这段。还是看下面的例子吧,运行一趟就知道了。 

    def math_by_anonymouse_block(a,b)
        yield a,b
    end
    
    def math_by_proc(a,b,a_proc)
        a_proc.call(a,b)
    end
    
    def math_by_named_block(a,b,&namedblock)
    
    		puts "math_by_proc a,b,namedblock"
    		puts namedblock.class # &namedblock 是一个区块,namedblock (去掉&)是一个proc,&操作符是个切换开关。
    		puts math_by_proc a,b,namedblock
    		puts "======="
    
    		#lambda
    		mylambda = lambda &namedblock
        puts mylambda.class
        puts math_by_anonymouse_block a,b,&mylambda
    		#哈哈,下面这样也可以
    		puts "math_by_proc a,b,mylambda"
    		puts math_by_proc a,b,mylambda
    		puts "======="
    
    		#proc
        myproc = proc &namedblock
        puts myproc.class
        puts math_by_anonymouse_block a,b,&myproc
    		#哈哈,下面这样也可以
    		puts "math_by_proc a,b,myproc"
    		puts math_by_proc a,b,myproc
    		puts "======="
    
        #puts &namedblock.class
    
    		#区块不能直接赋值给一个变量。但是可以通过方法来传递
        #myblock = &namedblock   #运行不通
        #puts myblock.class
    		#所以我们用这种方式
    		puts "math_by_anonymouse_block"
    		puts math_by_anonymouse_block a,b,&namedblock
    		puts "======="
    
    end
    
    math_by_named_block(2,3) {|x,y| x*y}
    

     

    运行结果:
    ---------- ruby run ----------
    math_by_proc a,b,namedblock
    Proc
    6
    =======
    Proc
    6
    math_by_proc a,b,mylambda
    6
    =======
    Proc
    6
    math_by_proc a,b,myproc
    6
    =======
    math_by_anonymouse_block
    6
    =======
    
    输出完成 (耗时 0 秒) - 正常终止
    

      

    区块就像是方法的额外匿名参数,任何方法在调用时,都可以在后面跟一个区块。只不过如果这个方法中有yield语句,它就会调用区块,如果没有yield语句,就无视这个区块。

    比如:

    def my_noyield
    
      puts "leave me alone. no yield !"
    
    end
    
    def my_yield
              
      puts "I call you! come on"
      yield
    
    end
    
    my_noyield { puts "I'm coming!"}
    
    my_yield { puts "I'm coming!"}
    

    这是我们来定义一个带&操作符参数的方法,这就等于把之前的匿名参数变成了一个 &变量名 的参数。这个参数是一个也必然必须是一个 区块(不是proc,去掉&才是proc)

    def my_third(&myproc)
    	puts "I call you! come on"
    	yield
    end
    
    my_third { puts "I'm coming!"}
    

    这里 &myproc 是个区块,而myproc是个proc。对于proc,我们应该可以直接调用proc.call.

    所以我们来试试第4个方法:不用yield,而在方法中直接call 这个proc

    def my_fourth (&myproc)
    	puts "I call you! come on"
    	myproc.call
    end
    
    my_fourth { puts "I'm coming!"}
    

    其实 &就是个切换开关,加上这个开关,就可以在proc和block之间切换。proc/lambda 也是一个开关(这两个是内核方法:Kernel#proc :Creates a new procedure object from the given block. Equivalent to Proc.new .)

    def my_fivth (&myproc)
    	puts "I call you! come on"
    	#&&myproc.call  这个不行,不能反转两次?
    	c_proc = proc &myproc
    	c_proc.call
    end
    
    my_fivth { puts "I'm coming!"}
    
    def my_sixth (&myproc)
    	puts "I call you! come on"
    	c_proc = lambda &myproc
    	c_proc.call
    end
    
    my_sixth { puts "I'm coming!"}
    

      

    补充一个小结:

    可调用对象,有以下几种形式:块,proc,lambda,方法。不同类的可调用对象有细微区别。

    但仍然可以通过以下方法在它们之间转换:包括Proc.new()方法,Methrod#to_proc()方法和&操作符。

  • 相关阅读:
    特斯拉PET钥匙-蓝牙无钥匙
    超声波倒车雷达
    KiCad层次原理图标签和引脚的操作
    Nuget常用命令
    TCP/IP协议入门
    unbuntu(18.04)下体验dotnet core
    c#中的异步
    Git的不完全使用指南
    c#语言特性8.0
    c#语言特性7.x
  • 原文地址:https://www.cnblogs.com/likeyu/p/2382879.html
Copyright © 2011-2022 走看看