• ruby 疑难点之—— yield 和 yield self


    yield

    所有的"方法(methods)"隐式跟上一个"块(block)"参数。

    块参数也可以明确给定,形式就是在参数前面加一个"&",比如 def fn(arg1, arg2, &block) end,其中的 &block 就是明确给定的块参数。

    块参数的动作,可以通过调用 call() 方法执行,还可以用 yield 来执行 —— yield 其实就是一个语法糖。

    所以以下几种写法常常是等价的:

    #method receives an invisible block argument
    def foo1()
        yield 1
    end
    
    #specify it explicitly
    def foo2(&block)
        yield 1
    end
    
    #yield is equal to block.call
    def foo3(&block)
        block.call(1)    
    end
    
    #function call
    foo1 {|x| puts x}    # => 1
    foo2 {|x| puts x}    # => 1
    foo3 {|x| puts x}    # => 1

    Proc

    前面说到所有方法都可以隐式或显式指定一个块参数,那么块参数到底是什么呢?

    答案是 Proc 对象,一个具有 call 方法的对象。

    Proc 对象的定义有几种形式:

    • 直接使用 {}
    • 使用 Proc.new {}
    • 使用 proc {}
    • 使用 lambda {}
    #yield is equal to block.call
    def foo(&block)
        puts block.class
        puts block.to_s
        yield 1    
    end
    
    #function call
    # Proc created using {} syntax
    foo {|x| puts x}   
    # => Proc
    # => #<Proc:0x00000000e0b140@(ruby):9>
    # => 1
    
    # Proc created with the "proc" keyword. Note & syntax when calling.
    my_proc = proc { |n| puts n }
    foo(&my_proc)
    # => Proc
    # => #<Proc:0x00000000e0b140@(ruby):12>
    # => 1
    
    # Proc creates with Proc.new
    my_proc = Proc.new { |n| puts n }
    foo(&my_proc)    # => 1
    # => Proc
    # => #<Proc:0x00000000e0b140@(ruby):16>
    # => 1
    
    # Proc created with the "lambda" keyword. Nearly same thing.
    my_proc = lambda { |n| puts n }
    foo(&my_proc)
    # => Proc
    # => #<Proc:0x00000000e0b140@(ruby):20 (lambda)>
    # => 1

    yield self

    在一个对象中,self 表示是一个当前对象的引用。

    所以,常见的 yield self if block_given? 中的 self 就和其它地方使用 self 一样,没什么特殊的。

    class C1
        def foo(&block)
            puts block.class
            puts block.to_s
            yield self if block_given?
            yield "AAAAAAAAA"
        end
    end
    
    class C2
        def foo(&block)
            puts block.class
            puts block.to_s
            yield self if block_given?
            yield "BBBBBBBBB"
        end
        
        def to_s
            "XXXXXXXXXX"
        end
    end
    
    c1 = C1.new
    c1.foo  {|x| puts x}
    # => Proc
    # => #<Proc:0x00000001c84aa0@(ruby):23>
    # => #<Context::C1:0x00000001c84af0>
    # => AAAAAAAAA
    
    c2 = C2.new
    c2.foo  {|x| puts x}
    # => Proc
    # => #<Proc:0x00000001c842f8@(ruby):26>
    # => XXXXXXXXXX
    # => BBBBBBBBB

    注意事项

    method 定义中 &block 参数必须在最后

    # 正确示例
    def foo(arg1, arg2, &block)
        puts block
    end
    
    #function call
    block = proc {|x| puts x}
    foo( 1, 2, &block)                   
    # => #<Proc:0x000000011f3aa0@(ruby):14>
    
    #错误示例
    def foo(arg1, &block, arg2)     # => (ruby): syntax error
        puts block
    end

    yield 相当于是 block.call() 方法的调用,所以参数个数也需要对应

    def foo()
        yield 1,2,3     # 这里的 1 2 3 就是传递的参数
    end
    
    #function call
    foo {|x| puts x}        # => 1
    foo {|x,y,z| puts z}    # => 3
    foo {|x,y,z,k| puts k}  # 为空
  • 相关阅读:
    在Linux下安装配置Oracle11g R2
    使用C#读取dbf行情文件
    终于完成了DailyBuild
    如何用NANT+FxCop 并生成文档规范检测结果?
    Nant中的一个小问题(可能让许多人急掉许多汗哦)
    最近在研究 Daily Build 不知道如何用CC.Net 得到 VSS改动的情况
    利用NAnt取得远程VSS服务器中的文件并且编译
    未曾秋高气爽,亦然爬山去也
    如何使用命令提示符下的FxCop
    在NAnt中加入Vssget 任务
  • 原文地址:https://www.cnblogs.com/licongyu/p/5522027.html
Copyright © 2020-2023  润新知