zoukankan      html  css  js  c++  java
  • 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}  # 为空
  • 相关阅读:
    Security and Cryptography in Python
    Security and Cryptography in Python
    Security and Cryptography in Python
    Security and Cryptography in Python
    Security and Cryptography in Python
    Security and Cryptography in Python
    Security and Cryptography in Python
    微信小程序TodoList
    C语言88案例-找出数列中的最大值和最小值
    C语言88案例-使用指针的指针输出字符串
  • 原文地址:https://www.cnblogs.com/licongyu/p/5522027.html
Copyright © 2011-2022 走看看