Ruby 2.4

Proc

class Proc

父:对象

Proc对象是已绑定到一组局部变量的代码块。一旦绑定,代码可能会在不同的上下文中调用并仍然访问这些变量。

def gen_times(factor) return Proc.new {|n| n*factor } end times3 = gen_times(3) times5 = gen_times(5) times3.call(12) #=> 36 times5.call(5) #=> 25 times3.call(times5.call(4)) #=> 60

公共类方法

new {|...| block } → a_proc Show source

new → a_proc

创建Proc绑定到当前上下文的新对象。Proc::new可能仅在具有附加块的方法内没有块被调用,在这种情况下该块被转换为Proc对象。

def proc_from Proc.new end proc = proc_from { "hello" } proc.call #=> "hello"

static VALUE rb_proc_s_new(int argc, VALUE *argv, VALUE klass) { VALUE block = proc_new(klass, FALSE rb_obj_call_init(block, argc, argv return block; }

公共实例方法

proc === obj → result_of_proc Show source

使用obj#call这样的proc参数调用该块。它允许proc对象when成为case语句中的子句的目标。

static VALUE proc_call(int argc, VALUE *argv, VALUE procval) { /* removed */ }

prcparams,... → obj Show source

调用该块,使用接近方法调用语义的东西将块的参数设置为params中的值。返回块中最后一个表达式的值。

a_proc = Proc.new {|scalar, *values| values.map {|value| value*scalar } } a_proc.call(9, 1, 2, 3) #=> [9, 18, 27] a_proc[9, 1, 2, 3] #=> [9, 18, 27] a_proc.(9, 1, 2, 3) #=> [9, 18, 27] a_proc.yield(9, 1, 2, 3) #=> [9, 18, 27]

请注意,prc.()调用prc.call()给定的参数。它是隐藏“呼叫”的语法糖。

对于使用创建的procs lambda或者->()如果将错误数量的参数传递给proc,则会生成错误。对于使用Proc.newor 创建的procs Kernel.proc,额外的参数被默默丢弃并且缺少参数被设置为nil。

a_proc = proc {|a,b| [a,b] } a_proc.call(1) #=> [1, nil] a_proc = lambda {|a,b| [a,b] } a_proc.call(1) # ArgumentError: wrong number of arguments (given 1, expected 2)

See also #lambda?.

static VALUE proc_call(int argc, VALUE *argv, VALUE procval) { /* removed */ }

arity → integer Show source

返回强制参数的数量。如果该块被声明为不带参数,则返回0.如果块已知需要正好n个参数,则返回n。如果该块具有可选参数,则返回-n-1,其中n是强制参数的数量,但不是lambda表达式且仅具有有限数量的可选参数的块除外; 在后一种情况下,返回n。关键字参数将被视为单个附加参数,如果任何关键字参数是强制参数,则该参数是必需参数。proc没有参数声明的A 与声明||为其参数的块相同。

proc {}.arity #=> 0 proc { || }.arity #=> 0 proc { |a| }.arity #=> 1 proc { |a, b| }.arity #=> 2 proc { |a, b, c| }.arity #=> 3 proc { |*a| }.arity #=> -1 proc { |a, *b| }.arity #=> -2 proc { |a, *b, c| }.arity #=> -3 proc { |x:, y:, z:0| }.arity #=> 1 proc { |*a, x:, y:0| }.arity #=> -2 proc { |x=0| }.arity #=> 0 lambda { |x=0| }.arity #=> -1 proc { |x=0, y| }.arity #=> 1 lambda { |x=0, y| }.arity #=> -2 proc { |x=0, y=0| }.arity #=> 0 lambda { |x=0, y=0| }.arity #=> -1 proc { |x, y=0| }.arity #=> 1 lambda { |x, y=0| }.arity #=> -2 proc { |(x, y), z=0| }.arity #=> 1 lambda { |(x, y), z=0| }.arity #=> -2 proc { |a, x:0, y:0| }.arity #=> 1 lambda { |a, x:0, y:0| }.arity #=> -2

static VALUE proc_arity(VALUE self) { int arity = rb_proc_arity(self return INT2FIX(arity }

binding → binding Show source

返回与prc关联的绑定。请注意,Kernel#eval接受一个Proc或一个Binding对象作为其第二个参数。

def fred(param) proc {} end b = fred(99) eval("param", b.binding) #=> 99

static VALUE proc_binding(VALUE self) { VALUE bindval, binding_self = Qundef; rb_binding_t *bind; const rb_proc_t *proc; const rb_iseq_t *iseq = NULL; const struct rb_block *block; const rb_env_t *env = NULL; GetProcPtr(self, proc block = &proc->block; again: switch (vm_block_type(block)) { case block_type_iseq: iseq = block->as.captured.code.iseq; binding_self = block->as.captured.self; env = VM_ENV_ENVVAL_PTR(block->as.captured.ep break; case block_type_proc: GetProcPtr(block->as.proc, proc block = &proc->block; goto again; case block_type_symbol: goto error; case block_type_ifunc: { const struct vm_ifunc *ifunc = block->as.captured.code.ifunc; if (IS_METHOD_PROC_IFUNC(ifunc)) { VALUE method = (VALUE)ifunc->data; binding_self = method_receiver(method iseq = rb_method_iseq(method env = VM_ENV_ENVVAL_PTR(block->as.captured.ep env = env_clone(env, method_cref(method) /* set empty iseq */ RB_OBJ_WRITE(env, &env->iseq, rb_iseq_new(NULL, rb_str_new2("<empty iseq>"), rb_str_new2("<empty_iseq>"), Qnil, 0, ISEQ_TYPE_TOP) break; } else { error: rb_raise(rb_eArgError, "Can't create Binding from C level Proc" return Qnil; } } } bindval = rb_binding_alloc(rb_cBinding GetBindingPtr(bindval, bind bind->block.as.captured.self = binding_self; bind->block.as.captured.code.iseq = env->iseq; bind->block.as.captured.ep = env->ep; if (iseq) { rb_iseq_check(iseq bind->path = iseq->body->location.path; bind->first_lineno = FIX2INT(rb_iseq_first_lineno(iseq) } else { bind->path = Qnil; bind->first_lineno = 0; } return bindval; }

call(params,...) → obj Show source

调用该块,使用接近方法调用语义的东西将块的参数设置为params中的值。返回块中最后一个表达式的值。

a_proc = Proc.new {|scalar, *values| values.map {|value| value*scalar } } a_proc.call(9, 1, 2, 3) #=> [9, 18, 27] a_proc[9, 1, 2, 3] #=> [9, 18, 27] a_proc.(9, 1, 2, 3) #=> [9, 18, 27] a_proc.yield(9, 1, 2, 3) #=> [9, 18, 27]

请注意,prc.()调用prc.call()给定的参数。它是隐藏“呼叫”的语法糖。

对于使用创建的procs lambda或者->()如果将错误数量的参数传递给proc,则会生成错误。对于使用Proc.newor 创建的procs Kernel.proc,额外的参数被默默丢弃并且缺少参数被设置为nil。

a_proc = proc {|a,b| [a,b] } a_proc.call(1) #=> [1, nil] a_proc = lambda {|a,b| [a,b] } a_proc.call(1) # ArgumentError: wrong number of arguments (given 1, expected 2)

See also #lambda?.

static VALUE proc_call(int argc, VALUE *argv, VALUE procval) { /* removed */ }

curry → a_proc Show source

curry(arity) → a_proc

返回一个curried过程。如果给出可选的arity参数,它将确定参数的数量。咖喱过程收到一些论据。如果提供了足够数量的参数,它将提供的参数传递给原始proc并返回结果。否则,返回另一个curried过程,其余的参数都会返回。

b = proc {|x, y, z| (x||0) + (y||0) + (z||0) } p b.curry[1][2][3] #=> 6 p b.curry[1, 2][3, 4] #=> 6 p b.curry(5)[1][2][3][4][5] #=> 6 p b.curry(5)[1, 2][3, 4][5] #=> 6 p b.curry(1)[1] #=> 1 b = proc {|x, y, z, *w| (x||0) + (y||0) + (z||0) + w.inject(0, &:+) } p b.curry[1][2][3] #=> 6 p b.curry[1, 2][3, 4] #=> 10 p b.curry(5)[1][2][3][4][5] #=> 15 p b.curry(5)[1, 2][3, 4][5] #=> 15 p b.curry(1)[1] #=> 1 b = lambda {|x, y, z| (x||0) + (y||0) + (z||0) } p b.curry[1][2][3] #=> 6 p b.curry[1, 2][3, 4] #=> wrong number of arguments (given 4, expected 3) p b.curry(5) #=> wrong number of arguments (given 5, expected 3) p b.curry(1) #=> wrong number of arguments (given 1, expected 3) b = lambda {|x, y, z, *w| (x||0) + (y||0) + (z||0) + w.inject(0, &:+) } p b.curry[1][2][3] #=> 6 p b.curry[1, 2][3, 4] #=> 10 p b.curry(5)[1][2][3][4][5] #=> 15 p b.curry(5)[1, 2][3, 4][5] #=> 15 p b.curry(1) #=> wrong number of arguments (given 1, expected 3) b = proc { :foo } p b.curry[] #=> :foo

static VALUE proc_curry(int argc, const VALUE *argv, VALUE self) { int sarity, max_arity, min_arity = rb_proc_min_max_arity(self, &max_arity VALUE arity; rb_scan_args(argc, argv, "01", &arity if (NIL_P(arity)) { arity = INT2FIX(min_arity } else { sarity = FIX2INT(arity if (rb_proc_lambda_p(self)) { rb_check_arity(sarity, min_arity, max_arity } } return make_curry_proc(self, rb_ary_new(), arity }

hash → integer Show source

返回对应于proc主体的散列值。

See also Object#hash.

static VALUE proc_hash(VALUE self) { st_index_t hash; hash = rb_hash_start(0 hash = rb_hash_proc(hash, self hash = rb_hash_end(hash return ST2FIX(hash }

inspect()

Alias for: to_s

lambda? → true or false Show source

true参数处理非常僵化的Proc对象的返回值。这样的过程通常由...生成lambda

通过proc忽略额外参数生成的Proc对象。

proc {|a,b| [a,b] }.call(1,2,3) #=> [1,2]

它提供nil了缺少的参数。

proc {|a,b| [a,b] }.call(1) #=> [1,nil]

它扩展了单个数组参数。

proc {|a,b| [a,b] }.call([1,2]) #=> [1,2]

生成的Proc对象lambda没有这种技巧。

lambda {|a,b| [a,b] }.call(1,2,3) #=> ArgumentError lambda {|a,b| [a,b] }.call(1) #=> ArgumentError lambda {|a,b| [a,b] }.call([1,2]) #=> ArgumentError

#lambda?是技巧的预言。true如果没有技巧适用,它会返回。

lambda {}.lambda? #=> true proc {}.lambda? #=> false

:: new与之相同proc

Proc.new {}.lambda? #=> false

lambdaprocand :: new保留了由&参数给定的Proc对象的技巧。

lambda(&lambda {}).lambda? #=> true proc(&lambda {}).lambda? #=> true Proc.new(&lambda {}).lambda? #=> true lambda(&proc {}).lambda? #=> false proc(&proc {}).lambda? #=> false Proc.new(&proc {}).lambda? #=> false

&参数生成的Proc对象具有技巧

def n(&b) b.lambda? end n {} #=> false

&如果一个Proc对象由给定的参数保留技巧&的说法。

n(&lambda {}) #=> true n(&proc {}) #=> false n(&Proc.new {}) #=> false

从方法转换的Proc对象没有技巧。

def m() end method(:m).to_proc.lambda? #=> true n(&method(:m)) #=> true n(&method(:m).to_proc) #=> true

define_method与方法定义相同。定义的方法没有技巧。

class C define_method(:d) {} end C.new.d(1,2) #=> ArgumentError C.new.method(:d).to_proc.lambda? #=> true

define_method总是定义一个没有技巧的方法,即使给出了非lambda Proc对象。这是窍门未被保留的唯一例外。

class C define_method(:e, &proc {}) end C.new.e(1,2) #=> ArgumentError C.new.method(:e).to_proc.lambda? #=> true

这个异常可以确保方法永远不会有技巧,并且使得包装器可以很容易地定义像往常一样运行的方法。

class C def self.def2(name, &body) define_method(name, &body) end def2(:f) {} end C.new.f(1,2) #=> ArgumentError

包装def2定义了一个没有技巧的方法。

VALUE rb_proc_lambda_p(VALUE procval) { rb_proc_t *proc; GetProcPtr(procval, proc return proc->is_lambda ? Qtrue : Qfalse; }

parameters → array Show source

返回此proc的参数信息。

prc = lambda{|x, y=42, *other|} prc.parameters #=> [[:req, :x], [:opt, :y], [:rest, :other]]

static VALUE rb_proc_parameters(VALUE self) { int is_proc; const rb_iseq_t *iseq = rb_proc_get_iseq(self, &is_proc if (!iseq) { return unnamed_parameters(rb_proc_arity(self) } return rb_iseq_parameters(iseq, is_proc }

source_location → String, Integer()

返回包含此proc的Ruby源文件名和行号,或者nil如果此proc未在Ruby中定义(即本机)。

VALUE rb_proc_location(VALUE self) { return iseq_location(rb_proc_get_iseq(self, 0) }

to_proc → proc Show source

将对象转换为Proc对象的协议的一部分。类的实例Proc只是返回自己。

static VALUE proc_to_proc(VALUE self) { return self; }

to_s → string Show source

返回此proc的唯一标识符,以及proc定义位置的指示。

static VALUE proc_to_s(VALUE self) { const rb_proc_t *proc; GetProcPtr(self, proc return proc_to_s_(self, proc }

别名: inspect

yield(params,...) → obj Show source

调用该块,使用接近方法调用语义的东西将块的参数设置为params中的值。返回块中最后一个表达式的值。

a_proc = Proc.new {|scalar, *values| values.map {|value| value*scalar } } a_proc.call(9, 1, 2, 3) #=> [9, 18, 27] a_proc[9, 1, 2, 3] #=> [9, 18, 27] a_proc.(9, 1, 2, 3) #=> [9, 18, 27] a_proc.yield(9, 1, 2, 3) #=> [9, 18, 27]

请注意,prc.()调用prc.call()给定的参数。它是隐藏“呼叫”的语法糖。

对于使用创建的procs lambda或者->()如果将错误数量的参数传递给proc,则会生成错误。对于使用Proc.newor 创建的procs Kernel.proc,额外的参数被默默丢弃并且缺少参数被设置为nil。

a_proc = proc {|a,b| [a,b] } a_proc.call(1) #=> [1, nil] a_proc = lambda {|a,b| [a,b] } a_proc.call(1) # ArgumentError: wrong number of arguments (given 1, expected 2)

See also #lambda?.

static VALUE proc_call(int argc, VALUE *argv, VALUE procval) { /* removed */ }