класс Continuation
Continuation объекты генерируются методом Kernel#callcc после запроса продолжения. Они содержат адрес возврата и контекст выполнения, позволяя выполнить возврат извне к концу блока callcc из любой точки программы. Продолжения чем-то похожи на структурированную версию setjmp/longjmp из C (хотя они содержат больше состояния, поэтому их можно считать ближе к потокам).
Например:
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 "#{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
Методы публичного экземпляра
Вызывает продолжение. Программа продолжает выполнение с конца блока 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 = cont_ptr(contval);
rb_thread_t *th = GET_THREAD();
if (cont_thread_value(cont) != th->self) {
rb_raise(rb_eRuntimeError, "continuation called across threads");
}
if (cont->saved_ec.fiber_ptr) {
if (th->ec->fiber_ptr != cont->saved_ec.fiber_ptr) {
rb_raise(rb_eRuntimeError, "continuation called across fiber");
}
}
cont->argc = argc;
cont->value = make_passing_arg(argc, argv);
cont_restore_0(cont, &contval);
UNREACHABLE_RETURN(Qnil);
} Вызывает продолжение. Программа продолжает выполнение с конца блока 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]
Ruby Core © 1993–2024 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.