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:[email protected](ruby):9>
# => 1

# Proc created with the "proc" keyword. Note & syntax when calling.
my_proc = proc { |n| puts n }
foo(&my_proc)
# => Proc
# => #<Proc:[email protected](ruby):12>
# => 1

# Proc creates with Proc.new
my_proc = Proc.new { |n| puts n }
foo(&my_proc)    # => 1
# => Proc
# => #<Proc:[email protected](ruby):16>
# => 1

# Proc created with the "lambda" keyword. Nearly same thing.
my_proc = lambda { |n| puts n }
foo(&my_proc)
# => Proc
# => #<Proc:[email protected](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:[email protected](ruby):23>
# => #<Context::C1:0x00000001c84af0>
# => AAAAAAAAA

c2 = C2.new
c2.foo  {|x| puts x}
# => Proc
# => #<Proc:[email protected](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:[email protected](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}  # 为空
时间: 2024-11-03 05:43:24

ruby 疑难点之—— yield 和 yield self的相关文章

Python3.4 yield 与 yield from

yield 语法 这一篇日志主要是参考Python 3: Using "yield from" in Generators. 上一篇博文介绍了yield的使用,现在在写一个例子: class Node: def __init__(self,value): self.left = [] self.value = value self.right = [] def node_iterate(self): for value in self.child_iterate(self.left):

60、简述 yield和yield from关键字。

1.可迭代对象与迭代器的区别 可迭代对象:指的是具备可迭代的能力,即enumerable.  在Python中指的是可以通过for-in 语句去逐个访问元素的一些对象,比如元组tuple,列表list,字符串string,文件对象file 等. 迭代器:指的是通过另一种方式去一个一个访问可迭代对象中的元素,即enumerator.在python中指的是给内置函数iter()传递一个可迭代对象作为参数,返回的那个对象就是迭代器,然后通过迭代器的next()方法逐个去访问. 2.生成器 生成器的本质

yield与yield from

yield 通过yield返回的是一个生成器,yield既可以产出值又可以生成值,yield可以用next()来启动生成器,同时可以用send向生成器传递值:在初次启动生成器时,需调用next()或send(None)来激活生成器,一个yield对应一个send或next(),当send或next()个数超过yield个数时,会抛出StopIteration 1 def gen_yield(): 2 value = yield 1 3 print(value) 4 value = yield 2

python yield、yield from与协程

从生成器到协程 协程是指一个过程,这个过程与调用方协作,产出由调用方提供的值.生成器的调用方可以使用 .send(...)方法发送数据,发送的数据会成为yield表达式的值.因此,生成器可以作为协程使用. 从句法上看,生成器与协程都是包含yield关键字的函数.但是,在协程中,yield通常出现在表达式的右边(* = yield *),可以产出值一可以不产出(yield关键字后边没有表达式,产出None). 协程有四个状态: GEN_CREATED:等待开始执行 GEN_RUNNING:正在执行

python yield 和 yield from用法总结

#例1. 简单输出斐波那契數列前 N 个数#缺点:该函数可复用性较差,因为 fab 函数返回 None,其他函数无法获得该函数生成的数列#要提高 fab 函数的可复用性,最好不要直接打印出数列,而是返回一个 List.def fab1(max):    n, a, b = 0, 0, 1    while n < max:        print(b,end=' ')        a, b = b, a + b        n = n + 1fab1(5) #例 2. #缺点:该函数在运行

yield return,yield break

转自, http://www.cnblogs.com/kingcat/archive/2012/07/11/2585943.html yield return 表示在迭代中下一个迭代时返回的数据,除此之外还有yield break, 其表示跳出迭代,为了理解二者的区别我们看下面的例子 class A : IEnumerable{    private int[] array = new int[10]; public IEnumerator GetEnumerator()    {       

C# yield return; yield break;

using System; using System.Collections; namespace YieldDemo { class Program { public static IEnumerable Power(int num, int exponent) { int counter = 0; int result = 1; while (counter++ < exponent) { //if (counter == 4) yield break; if (counter == 4)

Enumerator yielder.yield 与 Proc.yield 区别

最近看ruby cookbook遇到这个用法,google一下,这里原文解释 http://stackoverflow.com/questions/18865860/enumerator-yielder-yield-vs-proc-yield Enumerator yielder.yield VS Proc.yield The yield statement has no receiver. Inside a method it means "Run the block right now&qu

利用 Python yield 创建协程将异步编程同步化

在 Lua 和 Python 等脚本语言中,经常提到一个概念: 协程.也经常会有同学对协程的概念及其作用比较疑惑,本文今天就来探讨下协程的前世今生. 首先回答一个大家最关心的问题:协程的好处是什么? 通俗易懂的回答: 让原来要使用 异步 + 回调 方式写的非人类代码,可以用看似同步的方式写出来. 1.回顾同步与异步编程 同步编程即线性化编程,代码按照既定顺序执行,上一条语句执行完才会执行下一条,否则就一直等在那里. 但是许多实际操作都是CPU 密集型任务和 IO 密集型任务,比如网络请求,此时不