Spec-Zone.ru › Ruby 2.5

класс 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 "\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

Общедоступные методы экземпляров

cont[args, ...] Показать исходный код
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_thread_value(cont) != th->self) {
        rb_raise(rb_eRuntimeError, "continuation called across threads");
    }
    if (cont->saved_ec.protect_tag != th->ec->protect_tag) {
        rb_raise(rb_eRuntimeError, "continuation called across stack rewinding barrier");
    }
    if (cont->saved_ec.fiber_ptr) {
        if (th->ec->fiber_ptr != cont->saved_ec.fiber_ptr) {
            rb_raise(rb_eRuntimeError, "continuation called across fiber");
        }
    }
    rollback_ensure_stack(contval, th->ec->ensure_list, cont->ensure_array);

    cont->argc = argc;
    cont->value = make_passing_arg(argc, argv);

    cont_restore_0(cont, &contval);
    return Qnil; /* unreachable */
}

Вызывает продолжение. Программа продолжает выполнение с конца 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]
call(args, ...) Показать исходный код
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_thread_value(cont) != th->self) {
        rb_raise(rb_eRuntimeError, "continuation called across threads");
    }
    if (cont->saved_ec.protect_tag != th->ec->protect_tag) {
        rb_raise(rb_eRuntimeError, "continuation called across stack rewinding barrier");
    }
    if (cont->saved_ec.fiber_ptr) {
        if (th->ec->fiber_ptr != cont->saved_ec.fiber_ptr) {
            rb_raise(rb_eRuntimeError, "continuation called across fiber");
        }
    }
    rollback_ensure_stack(contval, th->ec->ensure_list, cont->ensure_array);

    cont->argc = argc;
    cont->value = make_passing_arg(argc, argv);

    cont_restore_0(cont, &contval);
    return Qnil; /* unreachable */
}

Вызывает продолжение. Программа продолжает выполнение с конца 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–2017 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API