• 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。反之,则最后一个参数为一个数组,该数组包含了剩余的传递参数;

  • 相关阅读:
    code第一部分数组:第十七题 爬楼梯问题
    code第一部分数组:第十六题 数组表示数,加一操作
    code第一部分数组:第十五题 矩阵翻转(图像翻转)
    code第一部分:数组 第十四题 雨水问题
    code第一部分数组:第十题:移除数组中目标元素
    [java 2020-04-24] Maven多模块项目+SpringBoot,编译失败:程序包xxx不存在
    [java 2020-04-24] springboot生成的jar包没有主类和依赖jar包
    [java 2019-12-16] SimpleDateFormat格式化跨年显示格式错误
    [2019-11-22]马说
    [linux 2019-10-23] linux可以创建多少个用户
  • 原文地址:https://www.cnblogs.com/zs-note/p/3347035.html
Copyright © 2020-2023  润新知