Proc类
Proc类是什么?
使块对象化的类
hello1 = Proc.new do |name|
puts "hello, #{name}"
end
hello2 = proc do |name|
puts "hello, #{name}"
end
hello1.call("Aaron")
hello2["Ruby"]
double = Proc.new do |*args|
args.map{|i| i * 2}
end
p double.call(1, 2, 3)
p double[1, 2, 3]
lambda
与proc的区别是,调用call方法时,参数数量必须与快的一致。而proc不要求。
prc1 = Proc.new do |a, b, c|
p [a, b, c]
end
prc1.call(1, 2)
#=> [1, 2, nil]
prc2 = lambda do |a, b, c|
p [a, b, c]
end
proc2.call(1, 2)
#=> 报错 ArgumentError
另一个区别,lambda可以使用return将值从块中返回。
def power_of(n)
lambda do |x|
#注意,返回的是Proc对象,而不是数值。
return x ** n
end
end
cube = power_of(3)
p cube.call(5)
#=> 125
#使用proc
def power_of(n)
Proc.new do |x|
return x ** n
end
end
cube = power_of(3)
p cube.call(5)
#=> 报错 LocalJumpError
另一种写法 ->
square = ->(n){ return n ** 2}
p square[5]
#=> 25
通过Proc参数接收块
def total2(from, to, &block)
result = 0
from.upto(to) do |num|
if block
result += block.call(num)
else
result += num
end
end
return result
end
p total2(1, 10)
p total2(1, 10) {|num| num ** 2}
to_proc
方法
#对符号:to_i使用Symbol#to_proc方法,会生成如下Proc对象
Proc.new{|arg| arg.to_i}
to_class = :class.to_proc
#=> Proc.new{|arg| arg.class}
p to_class.call("test") #=> String
p to_class.call(123) #=> Fixnum
p to_class.call( ** 1000) #=> Bignum
%w(42 39 56).map{|i| i.to_i }
%w(42 39 56).map{&:to_i }
[Integer, String, Array, Hash, File, IO].sort_by(&:name)
Proc的特征
#这就是传说中的闭包了。将处理内容、变量等环境同时进行保存的对象。
def counter
c = 0
Proc.new do
c += 1
end
end
c1 = counter
p c1.call #=> 1
p c1.call #=> 2
p c1.call #=> 3
c2 = counter
p c2.call #=> 1
p c2.call #=> 2
p c1.call #=> 4
Proc类的实例方法
prc.call(args, ...)
prc[args, ...]
prc.yield(args, ...)
prc.(args, ...)
prc===arg
调用方法
prc = Proc.new{|a, b| a + b}
p prc.call(1, 2)
p prc[3, 4]
p prc.yield(5, 6)
p prc.(7, 8)
p prc === [9, 10]
prc.arity
返回作为call方法参数的块变量个数
proc0 = Proc.new{ nil } #=> 0
proc1 = Proc.new{ |a| a } #=> 1
proc2 = Proc.new{ |a, b| a + b} #=> 2
proc4 = Proc.new{ |*args| args } #=> -1
prc.parameters
返回关于块变量的详细信息。返回值为[种类, 变量名]形式的数组
符号 | 意义 |
---|---|
:opt | 可省略的变量 |
:req | 必需的变量 |
:rest | 以*args形式表示的变量 |
:key | 关键字参数形式的变量 |
:keyrest | 以**args形式表示的变量 |
:block | 块 |
proc0 = proc{ nil }
proc1 = proc{ |a| a }
proc2 = lambda{ |a, b| [a, b]}
proc3 = lambda{ |a, b=1, *c| [a, b, c] }
proc4 = lambda{ |a, &block| [a, block] }
proc5 = lambda{ |a:1, **b| [a, b] }
p proc0.parameters #=> []
p proc1.parameters #=> [[:opt, :a]]
p proc2.parameters #=> [[:req, :a], [:req, :b]]
p proc3.parameters #=> [[:req, :a], [:opt, :b], [:rest, :c]]
p proc4.parameters #=> [[:req, :a], [:block, :block]]
p proc5.parameters #=> [[:key, :a], [:keyrest, :b]]
prc.lambda?
判断prc是否通过lambda定义的方法
prc1 = Proc.new{|a, b| a + b}
p prc1.lambda?
#=> false
prc2 = lambda{|a, b| a + b}
p prc2.lambda?
#=> true
prc.source_location
返回定义prc程序代码的位置。返回值为[代码文件名, 行编号]
prc0 = Proc.new { nil }
prc1 = Proc.new{ |a| a }
p prc0.source_location #=> ["/Users/Aaron/Desktop/learn.rb", 1]
p prc1.source_location #=> ["/Users/Aaron/Desktop/learn.rb", 2]