Ruby中的Proc类及Proc的类方法Proc.new的使用解析

Proc是对块及其context(局部变量的作用域以及栈框架)进行对象化处理之后得到的过程对象。您可以像使用无名函数那样来使用Proc,但它不会导入局部变量的作用域(可以把动态局部变量用作Proc局部变量)。

在下例中,正因为Proc一直保持着局部变量的作用域,所以才能调用var变量。

var = 1
$foo = Proc.new { var }
var = 2

def foo
 $foo.call
end

p foo    # => 2

从生成Proc的方法中返回以后,若Proc中出现return或retry的话,会引发LocalJumpError异常。

def foo
 proc { return }
end

foo.call
# => in `call': return from proc-closure (LocalJumpError)

def foo
 proc { retry }
end

foo.call
# => in `call': retry from proc-closure (LocalJumpError)

若在Proc前面加上"&"并将其传给一个带块的方法时,其运作情形类似于调用块。但从严格意义上讲,其间还存在以下不同。

# 没问题
(1..5).each { break }

# 在ruby 1.6.7, 1.8中没问题。在1.6.8中则发生异常
proc = Proc.new { break }
(1..5).each(&proc)

# 在ruby 1.6 中是 LocalJumpError
# 在ruby 1.8 中,再次运行each
proc = Proc.new { retry }
(1..5).each(&proc)
#=> retry from proc-closure (LocalJumpError)

这正是Proc对象用作调用块时的限制。

Proc.new
Proc.new { ... }

对块及其context进行对象化处理之后返回结果。

若没有给出块的话,就会把调用该方法的方法所带的块转换为Proc对象并将其返回。

def foo
  pr = Proc.new
  pr.call(1,2,3)
end
foo {|args| p args }
# => [1, 2, 3]

Proc.new方法深入
Proc.new对块及其context进行对象化处理之后返回结果。

若没有给出块的话,就会把调用该方法的方法所带的块转换为Proc对象并将其返回。

def foo
  pr = Proc.new
  pr.call(1,2,3)
end
foo {|args| p args }
# => [1, 2, 3]
这与下例相同
def foo
 yield(1,2,3)
end
foo {|args| p args }
# => [1, 2, 3]

若主调方法并没有带块时,则引发ArgumentError异常。

def foo
 Proc.new
end
foo
# => -:2:in `new': tried to create Proc object without a block (ArgumentError)
     from -:2:in `foo'
     from -:4

在使用Proc.new时,若定义了Proc#initialize方法的话,就在对象初始化时调用该方法。除此以外,它和proc是相同的。

利用 Proc.new 方法,或者对 proc 方法指定块,都可以创建代表块的 Proc 对象。

通过调用 Proc#call 方法执行块。调用 Proc#call 方法时的参数会作为块变量,块中最后一个表达式的值则为 Proc#call 的返回值。Proc#call 还有一个名称叫 Proc#[]。

# 判断西历的年是否为闰年的处理
leap = Proc.new do |year|
 year % 4 == 0 && year % 100 != 0 || year % 400 ==0
end
 
p leap.call(2000)  #=> true
p leap[2013]     #=> false
p leap[2016]     #=> true

将块变量设置为 |* 数组 | 的形式后,就可以像方法参数一样,以数组的形式接收可变数量的参数。

double = Proc.new do |*args|
 args.map{|i| i * 2 }  # 所有元素乘两倍
end
 
p double.call(1, 2, 3)  #=> [2, 3, 4]
p double[2, 3, 4]     #=> [4, 6, 8]

除此以外,定义普通方法时可使用的参数形式,如默认参数、关键字参数等,几乎都可以被用于块变量的定义,并被指定给 Proc#call 方法。

(0)

相关推荐

  • Ruby面向对象编程中类的方法与类的扩展

    类方法 类方法其实质是生活在该类的单件类中的单件方法.其定义方法有三种,分别是: # 法一 def MyClass.a_class_method; end # 法二 class MyClass def self.anther_class_method; end end # 法三* class MyClass class << self def yet_another_class_method; end end end 其中第三种方法道出了,类方法的实质,特别记忆一下! 类扩展 类扩展通过向类的

  • Ruby类实例变量、类实例方法和类变量、类方法的区别

    在Ruby中类实例变量.类实例方法和类变量.类方法的区别比较微妙,而且用法也有相当的区别.本文探讨一下他们的定义和基本的使用场景,以抛砖引玉...   一.类实例变量和类变量   类变量大家都很熟悉了,就是在类定义中用@@开头的变量.类变量是用于存储类的全局信息,它只属于类,不同与类实例变量(即用@开头定义的变量)每一个类的对象都有一份数据. 类变量是可以被继承的,也就是说如果我们派生一个子类,那么在子类中是可以访问父类的类变量的.子类和父类共享一份数据,对一个类的修改会反映到另一个类中.如下边

  • Ruby面向对象编程中类与方法的基础学习

    打开类和猴子补丁 在Ruby中,类定义的方法和其他的语句没有任何区别,都是一行一行的执行下去的.如下例子: class Example def method_1 puts "method 1" end end class Example def method_2 puts "method 2" end end 本例中,当第一次定义Class Example的时候,还没有一个叫做Example的Class存在,因此,Ruby开始定义这个类,当后面在定义这个类时,Rub

  • 详解Ruby中的单件方法和单件类

    单件方法 Ruby允许给单个对象增加方法,这种只针对单个对象生效的方法,称为单件方法 示例代码 str = "just a regular string" def str.title? self.upcase == self end str.title? # => false str.methods.grep(/title?/) # => [:title?] str.singleton_methods #=> [:title?] str.class # => S

  • Ruby中使用Block、Proc、lambda实现闭包

    闭包(Closure),是指未绑定到任何对象的自由代码,闭包中的代码与任何对象和全局变量无关,只与执行此段代码的上下文相关. 今天我们简要的看一下ruby中的闭包实现. Ruby中的闭包实现有:Block,Proc,Lambada. 首先,我们来看Block. 复制代码 代码如下: ary = [1,2,3,4] ary.collect! do |a| a*a end ary.each do |a| puts a end 这段代码,我们使用了Array对象的block方法,将ary中的每个元素平

  • 浅析Ruby中的类对象的概念

    面向对象的程序涉及类和对象. 一个类是蓝本,从个别对象被创建.在面向对象的术语,我们说小明的自行车是被称为自行车类的对象实例. 任何车辆的例子.它包括轮子,马力,燃油或燃气罐容量.这些特点形成的类车辆的数据成员.可以从其他车辆区分这些特征. 车辆也有一定的功能,如停止,驾驶,超速驾驶.即使这些功能形成的类车辆的数据成员.因此,可以定义一个类作为一个组合的特点和功能. 车辆类可以被定义为: Class Vehicle { Number no_of_wheels Number horsepower

  • 简单的Ruby中的Socket编程教程

    Ruby提供了两个级别访问网络的服务,在底层你可以访问操作系统,它可以让你实现客户端和服务器为面向连接和无连接协议的基本套接字支持. Ruby 统一支持应用程的网络协议,如FTP.HTTP等. 不管是高层的还是底层的.ruby提供了一些基本类,让你可以使用TCP,UDP,SOCKS等很多协议交互,而不必拘泥在网络层.这些类也提供了辅助类,让你可以轻松的对服务器进行读写. 接下来就让我们来学习如何进行 Ruby Socket 编程 什么是 Sockets 应用层通过传输层进行数据通信时,TCP和U

  • Ruby中的Proc类及Proc的类方法Proc.new的使用解析

    Proc是对块及其context(局部变量的作用域以及栈框架)进行对象化处理之后得到的过程对象.您可以像使用无名函数那样来使用Proc,但它不会导入局部变量的作用域(可以把动态局部变量用作Proc局部变量). 在下例中,正因为Proc一直保持着局部变量的作用域,所以才能调用var变量. var = 1 $foo = Proc.new { var } var = 2 def foo $foo.call end p foo # => 2 从生成Proc的方法中返回以后,若Proc中出现return或

  • Ruby中的block、proc、lambda区别总结

    在规则引擎中,Ruby 的闭包使用特别频繁,而且有 block,Proc和 lambda 等后几种形式的用法,很让人困惑.为了深入理解代码,再次认真学习了一下 Ruby 的闭包,特别是 block,proc 和 lambda 几种用法的异同,这次的周记就和大家分享一下心得. 闭包是 Ruby 相对其它语言特别优势之一,很多语言有闭包,但是唯有 Ruby 把闭包的优势发挥得淋漓尽致.Ruby 的哲学之一:同一个问题现实中有多种解决方法,所以 Ruby 中也有多种解法,所以闭包的使用也有多种方法.

  • 详解Ruby中的代码块对象Proc

    Proc对象 Proc是由块转换来的对象.创建一个Proc共有四种方法,分别是: 示例代码 # 法一 inc = Proc.new { | x | x + 1} inc.call(2) #=> 3 # 法二 inc = lambda {| x | x + 1 } inc.call(2) #=> 3 # 法三 inc = ->(x) { x + 1} inc.call(2) #=> 3 # 法四 inc = proc {|x| x + 1 } inc.call(2) #=> 3

  • 在Ruby中利用Net::SMTP类发送电子邮件的教程

    简单邮件传输协议(SMTP)发送电子邮件及路由的e-mail邮件服务器之间的协议处理. Ruby 提供 Net::SMTP 类的简单邮件传输协议(SMTP)客户端的连接,并提供了两个新的方法:new 和 start. new 带两个参数: server name 默认为 localhost port number  默认为熟知的 25 start 方法带有以下这些参数: server - IP SMTP服务器名称,默认为localhost port - 端口号,默认为25 domain - 邮件

  • 进一步深入Ruby中的类与对象概念

    Ruby是纯面向对象的语言,所有项目似乎要Ruby中为一个对象.Ruby中的每个值是一个对象,即使是最原始的东西:字符串,数字甚至true和false.即使是一个类本身是一个对象,它是Class类的一个实例.本章将通过所有功能涉及到Ruby的面向对象. 类是用来指定对象的形式,它结合了数据表示和方法操纵这些数据,转换成一个整齐的包.在一个类的数据和方法,被称为类的成员. Ruby类的定义: 定义一个类,定义的数据类型的草图. 这实际上并不定义任何数据,但它定义的类名字的意思什么,即是什么类的对象

  • 深入理解Ruby中的代码块block特性

    block是什么? 在Ruby中,block并不罕见.官方对block的定义是"一段被包裹着的代码".当然,我觉得这样的解释不会让你变的更明白. 对block的一种更简单的描述是"一个block就是一段存储在一个变量中的代码,它和其他的对象一样,可以被随时的运行" 然后,咱们通过看一些代码,之后再把这些代码重构成Ruby中的block形式.通过代码来实际的感受,更加直观. 比如,对两个数做加法? puts 5 + 6 # => 11 嗯,这样写是可以的.但是,

随机推荐