Continuation
Continuation类
Parent:Object
继续对象由Kernel#callcc在+ require + d延续之后生成。 它们拥有一个返回地址和执行上下文,允许非本地从程序中的任何位置返回到callcc块的末尾。 持续有点类似于C的setjmp / longjmp的结构化版本(尽管它们包含更多的状态,所以你可能会认为它们更接近线程)。
例如:
require "continuation"
arr = [ "Freddie", "Herbie", "Ron", "Max", "Ringo" ]
callcc{|cc| $cc = cc}
puts(message = arr.shift)
$cc.call unless message =~ /Max/
产生结果:
Freddie
Herbie
Ron
Max
你也可以用其他方法调用callcc:
require "continuation"
def g
arr = [ "Freddie", "Herbie", "Ron", "Max", "Ringo" ]
cc = callcc { |cc| cc }
puts arr.shift
return cc, arr.size
end
def f
c, size = g
c.call(c) if size > 1
end
f
这个(人为的)例子允许内部循环提前放弃处理:
require "continuation"
callcc {|cont|
for i in 0..4
print "\n#{i}: "
for j in i*5...(i+1)*5
cont.call() if j == 17
printf "%3d", j
end
end
}
puts
产生结果:
0: 0 1 2 3 4
1: 5 6 7 8 9
2: 10 11 12 13 14
3: 15 16
公共实例方法
contargs, ...()
调用延续。该程序从该callcc
块的末尾继续。如果没有给出参数,则原始callcc
返回nil
。如果给出一个参数,则callcc
返回它。否则,返回一个包含args
的数组。
callcc {|cont| cont.call } #=> nil
callcc {|cont| cont.call 1 } #=> 1
callcc {|cont| cont.call 1, 2, 3 } #=> [1, 2, 3]
static VALUE
rb_cont_call(int argc, VALUE *argv, VALUE contval)
{
rb_context_t *cont;
rb_thread_t *th = GET_THREAD(
GetContPtr(contval, cont
if (cont->saved_thread.self != th->self) {
rb_raise(rb_eRuntimeError, "continuation called across threads"
}
if (cont->saved_thread.protect_tag != th->protect_tag) {
rb_raise(rb_eRuntimeError, "continuation called across stack rewinding barrier"
}
if (cont->saved_thread.fiber) {
if (th->fiber != cont->saved_thread.fiber) {
rb_raise(rb_eRuntimeError, "continuation called across fiber"
}
}
rollback_ensure_stack(contval, th->ensure_list, cont->ensure_array
cont->argc = argc;
cont->value = make_passing_arg(argc, argv
/* restore `tracing' context. see [Feature #4347] */
th->trace_arg = cont->saved_thread.trace_arg;
cont_restore_0(cont, &contval
return Qnil; /* unreachable */
}
call(args, ...) Show source
调用延续。 该程序从callcc块的末尾继续。 如果没有给出参数,则原始callcc返回nil。 如果给出一个参数,callcc会返回它。 否则,返回一个包含args的数组。
callcc {|cont| cont.call } #=> nil
callcc {|cont| cont.call 1 } #=> 1
callcc {|cont| cont.call 1, 2, 3 } #=> [1, 2, 3]
static VALUE
rb_cont_call(int argc, VALUE *argv, VALUE contval)
{
rb_context_t *cont;
rb_thread_t *th = GET_THREAD(
GetContPtr(contval, cont
if (cont->saved_thread.self != th->self) {
rb_raise(rb_eRuntimeError, "continuation called across threads"
}
if (cont->saved_thread.protect_tag != th->protect_tag) {
rb_raise(rb_eRuntimeError, "continuation called across stack rewinding barrier"
}
if (cont->saved_thread.fiber) {
if (th->fiber != cont->saved_thread.fiber) {
rb_raise(rb_eRuntimeError, "continuation called across fiber"
}
}
rollback_ensure_stack(contval, th->ensure_list, cont->ensure_array
cont->argc = argc;
cont->value = make_passing_arg(argc, argv
/* restore `tracing' context. see [Feature #4347] */
th->trace_arg = cont->saved_thread.trace_arg;
cont_restore_0(cont, &contval
return Qnil; /* unreachable */
}