最早看到yield时,就用c/C++中的概念对比了一番,发现最接近就是“宏代码的展开”。粗看起来,这样的理解是可以的。不过马上就有个问题出来了,就是定义域。宏代码的展开,要求展开后的代码处于被展开的位置同一个定义域,否则,相关变量和函数就会出现没有定义的错误。 不过从下面的ruby代码来看,yield没有这样的问题存在
[code]class A
def self.test
yield
end
end
class B
def test0
puts "call from class B"
end
def test1
A.test {test0}
end
end
b = B.new
b.test1[/code]
如果以代码展开的角度来理解上面代码的运行,那么就应该出现test0 不是A的函数这样的错误提示。不过运行下来很成功,没有出现任何错误。
还有一种可能是ruby的函数调用,就像C++一样,默认附带一个this对象。
[code]def test1
A.test {test0}
end[/code]
这段代码在执行时是不是被修改成了
[code]def test1
A.test {@this.test0}
end[/code]
ruby如果真有这个功能,上面代码的执行似乎能够说的通。
不过上面都是猜测,看下《Programming Ruby - 2nd》第一次提到yield的时候得说明
[quote]First, a block may appear only in the source adjacent to a method call; the block is written starting on the same line as the method call’s last parameter (or the closing parenthesis of the parameter list). Second, the code in the block is not executed at the time it is encountered. [color=red]Instead, Ruby remembers the context in which the block appears (the local variables, the current object, and so on)[/color] and then enters the method. This is where the magic starts.
Within the method, the block may be invoked, [color=red]almost as if it were a method itself[/color], using the yield statement. Whenever a yield is executed, it invokes the code in the block.When the block exits, [color=red]control picks back up immediately after the yield.[/color]1 Let’s start
with a trivial example.
def three_times
yield
yield
yield
end
three_times { puts "Hello" }
produces:
Hello
Hello
Hello
[/quote]
这段文字提到了3点。
第一,保存block相关的context
第二,block调用像函数本身的一部分
第三,有个神秘的control在操纵这一切
如果第一点,可以看作ruby给test0附加了个this对象,但是第二第三个就说不通了,如果只是代码展开,第二第三就不需要说明了。[color=red]看来关于yield是代码展开的想法是完全错的。[/color]
那么从第三点来看,yield的确有个代码运行块(先这样叫着)切换的动作,最后运行完了又切换回来.
加入代码切换的说法之后,给出的例子代码似乎是这样运行的
1.运行A.test的上半部分直到遇到yield
2.写入block的context,同时使用block的context和A.test运行到一半的context,作为block的运行环境来运行block代码,
3.block运行完毕,清除block的context,然后继续运行A.test的下半部分。
古怪阿古怪,yield是真的这样运行的吗?
从前面yield的翻译讨论来看,yield带有切换,退让,让步这类的意思。
yield如果有执行代码切换的功能,多少带有超级微型线程的意思了。而且是主动切换,执行代码主体。[color=red]yield完全是一个控制代码执行顺序的关键字了[/color]。真神奇。
:idea:
[code]class A
def self.test
yield
end
end
class B
def test0
puts "call from class B"
end
def test1
A.test {test0}
end
end
b = B.new
b.test1[/code]
如果以代码展开的角度来理解上面代码的运行,那么就应该出现test0 不是A的函数这样的错误提示。不过运行下来很成功,没有出现任何错误。
还有一种可能是ruby的函数调用,就像C++一样,默认附带一个this对象。
[code]def test1
A.test {test0}
end[/code]
这段代码在执行时是不是被修改成了
[code]def test1
A.test {@this.test0}
end[/code]
ruby如果真有这个功能,上面代码的执行似乎能够说的通。
不过上面都是猜测,看下《Programming Ruby - 2nd》第一次提到yield的时候得说明
[quote]First, a block may appear only in the source adjacent to a method call; the block is written starting on the same line as the method call’s last parameter (or the closing parenthesis of the parameter list). Second, the code in the block is not executed at the time it is encountered. [color=red]Instead, Ruby remembers the context in which the block appears (the local variables, the current object, and so on)[/color] and then enters the method. This is where the magic starts.
Within the method, the block may be invoked, [color=red]almost as if it were a method itself[/color], using the yield statement. Whenever a yield is executed, it invokes the code in the block.When the block exits, [color=red]control picks back up immediately after the yield.[/color]1 Let’s start
with a trivial example.
def three_times
yield
yield
yield
end
three_times { puts "Hello" }
produces:
Hello
Hello
Hello
[/quote]
这段文字提到了3点。
第一,保存block相关的context
第二,block调用像函数本身的一部分
第三,有个神秘的control在操纵这一切
如果第一点,可以看作ruby给test0附加了个this对象,但是第二第三个就说不通了,如果只是代码展开,第二第三就不需要说明了。[color=red]看来关于yield是代码展开的想法是完全错的。[/color]
那么从第三点来看,yield的确有个代码运行块(先这样叫着)切换的动作,最后运行完了又切换回来.
加入代码切换的说法之后,给出的例子代码似乎是这样运行的
1.运行A.test的上半部分直到遇到yield
2.写入block的context,同时使用block的context和A.test运行到一半的context,作为block的运行环境来运行block代码,
3.block运行完毕,清除block的context,然后继续运行A.test的下半部分。
古怪阿古怪,yield是真的这样运行的吗?
从前面yield的翻译讨论来看,yield带有切换,退让,让步这类的意思。
yield如果有执行代码切换的功能,多少带有超级微型线程的意思了。而且是主动切换,执行代码主体。[color=red]yield完全是一个控制代码执行顺序的关键字了[/color]。真神奇。
:idea: