非常教程

Ruby 2.4参考手册

Proc

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 */
}
Proc
Ruby 2.4

Ruby 是一种面向对象、命令式、函数式、动态的通用编程语言,是世界上最优美而巧妙的语言。

主页 https://www.ruby-lang.org/
源码 https://github.com/ruby/ruby
版本 2.4
发布版本 2.4.1

Ruby 2.4目录

1.缩略 | Abbrev
2.ARGF
3.数组 | Array
4.Base64
5.基本对象 | BasicObject
6.基准测试 | Benchmark
7.BigDecimal
8.绑定 | Binding
9.CGI
10.类 | Class
11.比较 | Comparable
12.负责 | Complex
13.计算续体 | Continuation
14.覆盖 | Coverage
15.CSV
16.日期 | Date
17.日期时间 | DateTime
18.DBM
19.代理 | Delegator
20.摘要 | Digest
21.Dir
22.DRb
23.编码 | Encoding
24.枚举 | Enumerable
25.枚举 | Enumerator
26.ENV
27.ERB
28.错误 | Errors
29.Etc
30.期望值 | Exception
31.错误类 | FalseClass
32.Fiber
33.Fiddle
34.文件 | File
35.文件实用程序 | FileUtils
36.查找 | Find
37.浮点 | Float
38.Forwardable
39.GC
40.GDBM
41.GetoptLong
42.Hash
43.Integer
44.IO
45.IPAddr
46.JSON
47.Kernel
48.语言 | 3Language
49.记录 | Logger
50.编排 | Marshal
51.MatchData
52.数学 | Math
53.矩阵 | Matrix
54.方法 | Method
55.模型 | Module
56.监控 | Monitor
57. 互斥 | Mutex
58.Net
59.Net::FTP
60.Net::HTTP
61.Net::IMAP
62.Net::SMTP
63.NilClass
64.数字 | Numeric
65.对象 | Object
66.ObjectSpace
67.Observable
68.Open3
69.OpenSSL
70.OpenStruct
71.OpenURI
72.OptionParser
73.路径名 | Pathname
74.完整输出 | PrettyPrint
75.Prime
76.Proc
77.过程 | Process
78.PStore
79.PTY
80.队列 | Queue
81.随机 | Random
82.范围 | Range
83.合理的 | Rational
84.Readline
85.Regexp
86.Resolv
87.Ripper
88.RubyVM
89.Scanf
90.SDBM
91.SecureRandom
92.Set
93.Shell
94.信号 | Signal
95.Singleton
96.套接字 | Socket
97.字符串 | String
98.StringIO
99.StringScanner
100.结构 | Struct