zoukankan      html  css  js  c++  java
  • Ruby代码块(Block)

    1、什么是代码块

            在Ruby中,{}或do...end之间的代码是一个代码块。代码块只能出现在一个方法的后边,它紧接在方法最后一个参数的同一行上,由yield关键字调用。例如:

    [1,2,3,4,5].each { |i| puts i }
    
    [1,2,3,4,5].each do |i| 
    puts i
    end

    块变量:以yield关键字调用block也可以传递参数,block中竖线(|)之间给出的参数名用于接收来自yield的参数。

                 竖线之间(如上例中的 | i |)的变量被称作块变量,作用和一个正常方法的参数一样

    2、{}和do...end优先级不同

           在传递一个block时,使用{}传递的block比使用do…end的优先级要高;

    为了避免引起歧义,最好使用()将参数括起来。例如:

    1.upto 3 do |x|
      puts x
    end

    是正确的,但是 1.upto 3 {|x| puts x} 编译不通过,应该写成   1.upto(3) {|x| puts x}

     原因:

    1.upto 3 do…end 中block会传递到upto方法里面,3会作为一个参数传递给upto

    1.upto 3 {|x| puts x} 一句会把3当做函数名,将block传递到这个函数,其返回值作为upto方法的参数,所以编译不过,需加()。

    3、代码块转化为对象的方法

    代码块并不是对象,但可以通过以下三种方法转化为Proc类的对象:

    (1)将一个代码块传递给最后一个参数以 & 开始的方法。例:

    def meth1(p1, p2, &block)
      puts block.inspect
      puts block.call
    end
    meth1(1, 2) { "This is a block" }

    (2)使用Proc.new方法,代码块作为参数:

    block = Proc.new { "a block" }

    (3)调用Kernel.lambda方法:

    block = lambda { "a block" }

        前两种方法是等价的,会检查参数的数量,但Proc.new 创建的对象不会;

    用 lambda 和 Proc.new 生成的 Proc 对象之间也是有差别的。这个差别与 return 关键字相关。lambda 中的 return 从 lambda 返回。而 Proc.new 中的 return 从外围方法返回。

    # 执行后"Never come here"不会被输出,执行p.call相当于在test_proc方法内执行了return语句。
    def test_proc
      p = Proc.new { return 1 } # test_proc方法返回
      p.call 
      puts "Never come here" # 永远不会执行到
    end
    
    # 使用lambda生成的Proc对象执行call方法调用时,return表示从lambda包围得块内返回。
    def test_lambda
      p = lambda { return 1 }
      result = p.call
      puts "The value is: #{result}"
    end

    Note:在一个代码块中执行next语句会导致代码块返回。返回值就是next语句后带的参数。如果next后没有参数,那么返回值为nil。

    def meth2
      result = yield
      p "The block result is #{result}"
    end
    
    puts meth2 { next 9 } 
    pr = Proc.new { next 100 }
    puts pr.call
    pr = lambda { next }
    puts pr.call
    
    执行结果为:
    The block result is 9
    100
    nil

    4、yield关键字调用代码块

    在方法中可以使用 yield 来执行代码块的内容,就好像传入的代码块是这个方法的一部分一样。每当碰到一个 yield,代码块的内容就会被执行一次,代码块执行结束后,程序会回到 yield 的那一行继续向下执行。
        使用 yield 可以向代码块传递参数,也可以从代码块取回返回值,返回值就是代码块中最后一个表达式的值。
    def fibonacii(max)
      f1, f2 = 1, 1
      while f1 <= max
        yield f1
        f1, f2 = f2, f1+f2
      end
    end
    
    fibonacii(1000) { |f| print f, " " }
    
    执行结果为:
    1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987

    (1)在这个例子中,yield 接收一个参数f1,这个参数将会在执行的时候传递给指定的代码块。在代码块中,接收的参数使用两个竖线括起来放在代码块的头部。

    (2)另外,在使用 yield 关键字调用代码块时,如果传入的参数个数少于代码块中定义的参数个数,那么没有传递的参数会自动转为nil。反之,则最后一个参数为一个数组,该数组包含了剩余的传递参数;

  • 相关阅读:
    RocketMQ源码分析:(二)消息发送的三种方式
    LTS本地搭建详述
    Mac端解决(含修改8.0.13版的密码):Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)
    flink入门:01 构建简单运行程序
    rocketmq控制台搭建(rocketmq-console)
    在consul上注册web服务
    将filenames里的每个字符串输出到out文件对象中注意行首的缩进
    spidermark sensepostdata ntp_monlist.py
    HTTP Error 403没有了,但是中文全都是乱码。又是怎么回事?
    original.txt和提交的页面输出的文字的混合文件
  • 原文地址:https://www.cnblogs.com/zs-note/p/3347035.html
Copyright © 2011-2022 走看看