`
magixyu
  • 浏览: 79818 次
  • 性别: Icon_minigender_1
  • 来自: 青岛
社区版块
存档分类
最新评论

Advanced Rails -- Ruby 基本技术(5) -- Ruby 基础4

    博客分类:
  • ROR
阅读更多
Block, Method and Proc
Ruby的一个很强大的功能就是有把一小片代码作为对象处理的能力。一共有如下的3类:

Proc:
一个Proc表现为一个代码块,这个代码块可以带参数调用,并且给出一个返回值。

UnboundMethod:
和Proc比较象。它表现为一个类的实例方法。(要注意的是类方法是一个类对象的实例方法,所以UnboundMethod也可以表现为类方法)。一个UnboundMethod在调用前一定要bound到一个类。

Method:
Method 对象是以经通过UnboundMethod#bound 而bound到一个对象的UnboundMethods。还有,他也可以通过Object#method。

我们看一下几种得到Proc和Method对象的方法。下面用Fixnum#+ 作为一个例子。我们一般用双值语法调用他。

	3 + 5 # => 8


我们可以用实例方法类调用,如:

	3.+(5) # => 8 


我们可以用Object#method来得到类的这个实例方法的表现。这个方法会bound到method被调用的对象,3。

	add_3 = 3.method(:+)
	add_3 # => #<Method: Fixnum#+>


这个方法也能转化为Proc,或者直接加参数调用。

	add_3.to_proc # => #<Proc:0x00024b08@-:6>
	add_3.call(5) # => 8
	# Method#[] is a handy synonym for Method#call.
	add_3[5] # => 8


有两种方式可以得到unbound method。一是对对象调用instance_method

	add_unbound = Fixnum.instance_method(:+)
	add_unbound # => #<UnboundMethod: Fixnum#+>


我们也可以unbind一个已经被bound到一个对象的方法

	add_unbound == 3.method(:+).unbind # => true
	add_unbound.bind(3).call(5) # => 8 


也可以bind这个UnboundMethod到任何一个同一个类的对象

	add_unbound.bind(15)[4] # => 19


当然,bind的对象碧血是一个同一个实例,不然会得到一个TypeError的异常

	add_unbound.bind(1.5)[4] # =>
	# ~> -:16:in 'bind': bind argument must be an instance of Fixnum (TypeError)
	# ~> from -:16


得到这个错误的原因是 + 在Fixnum里定义了,这个UnboundMethod对象必须bound到一个kind_of?(Fixnum)的对象。+ 在Numeric定义了(继承Fixnum和Float),上面的代码会得到5.5

block Proc 的转换

当前Ruby执行的一个downside: Block不一定是Proc,反之亦然。普通的block(用do...end或者{}创建的)一定要附在一个方法调用上,并且不是自动对象。比如,不能定义code_block={puts "abc"}。这些是Kernel#lambda和Proc.new 可以做的:把block转化为Proc

Kernel#proc 是 Kernel#lambda别名,但是要废弃了。
	block_1 = lambda { puts "abc" } # => #<Proc:0x00024914@-:20>
	block_2 = Proc.new { puts "abc" } # => #<Proc:0x000246a8@-:21>



在Kernel#lambda和Proc.new有一点的不同。用Kernel#lambda产生的Proc是把值返回到调用它的函数;而用Proc.new创建的Proc会使调用它的函数返回,如果失败就会引发一个LocalJumpError的异常,看下面的例子:

	def block_test
	  lambda_proc = lambda { return 3 }
	  proc_new_proc = Proc.new { return 4 }

	  lambda_proc.call # => 3
	  proc_new_proc.call # =>

	  puts "Never reached"
	end
	
	block_test # => 4 



lambda_proc的return语句在lambda里返回了3。相反地,在proc_new_proc的return语句在调用函数block_test里return了,因此block_test返回了4。下面的puts语句不会被执行,因为proc_new_proc.call语句已经在block_test中返回了。

也可以通过把Block传递给一个函数也可以把Block转化成Proc,在函数正常的参数前加&:

	def some_function(&b)
	  puts "Block is a #{b} and returns #{b.call}"
	end

	some_function { 6 + 3 }
	# >> Block is a #<Proc:0x00025774@-:7> and returns 9


相对的,也可以在函数需要一个block的时候用&替换Proc:

	add_3 = lambda {|x| x+3}
	(1..5).map(&add_3) # => [4, 5, 6, 7, 8]


闭包

闭包是在当一个block或者Proc访问在其范围之外的变量的时候创建的。即使包含的代码块出了作用域的范围,这些变量会一直存在当引用他们block或者Proc也出了作用域之后。一个简单的例子,只是说明这个原理:

	def get_closure
	  data = [1, 2, 3]
	  lambda { data }
	end
	block = get_closure
	block.call # => [1, 2, 3]


在get_closure返回的匿名方法引用了局部的变量数据,这些数据是在匿名方法职位定义的。当这个块变量在作用域,它会保持它自己对这个数据的引用,这个数据的实例会被删除(即使get_closure返回了)。要注意的是每次get_closure被调用的时候,数据引用一个不同的变量(它是一个函数局部的变量):

	block = get_closure
	block2 = get_closure

	block.call.object_id # => 76200
	block2.call.object_id # => 76170



函数make_counter是一个典型的闭包的例子。这个函数返回了一个计数函数。每次执行的都会增加并且返回当前的数值。在Ruby里,make_counter是类似的实现:

	def make_counter(i=0)
	  lambda { i += 1 }
	end

	x = make_counter
	x.call # => 1
	x.call # => 2

	y = make_counter
	y.call # => 1
	y.call # => 2


这个lambda函数创建了一个闭包,这个壁报包含了当前的局部变量i。不仅仅这个变量是可以访问的,他的值也是可以修改的。每一个闭包得到一个不用的变量的实例(因为这个变量是对应于一个make_counter的实例)。因为x和y包含一个对局部变量i实例的引用,他们有不同的状态。

分享到:
评论

相关推荐

    Advanced Rails

    "Advanced Rails" 涵盖了Rails开发中的高级主题和技术,是Ruby on Rails学习进阶的重要资源,尤其适合已经对基础Rails有一定了解的开发者。 在Web开发领域,Rails以其高效、简洁的代码和“约定优于配置”的哲学吸引...

    rails2-sample

    这一章节为读者提供了Ruby on Rails框架的基本认识。Ruby on Rails是一种基于Ruby语言的开源Web应用框架,遵循MVC(Model-View-Controller)设计模式。它以其优雅的语法、高效的开发速度以及“约定优于配置”的理念...

    Ruby-LockboxRuby和Rails的文件加密

    Ruby-Lockbox是一款针对Ruby和Rails应用的安全库,主要用于实现文件和数据的加密。它提供了简单易用的接口,让开发者能够轻松地在应用程序中集成高级加密标准(AES)和其他密码学算法,确保敏感信息的安全性。 Ruby...

    Advanced Rails Recipes(随书源码)

    (Ruby Recipeswas is written for Rails 1.x,this book for Rails 2.0.) Ruby on Rails continues to build up a tremendous head of steam. Fueled by significant benefits and an impressive portfolio of real...

    Advanced Rails Recipes

    该书面向已经具备一定Rails开发基础的技术人员,提供了深入且实用的技术指导。 **描述:“Advanced Rails Recipes 正式版。不要资源分,免费提供,要下的赶快哦。。。”** 这段描述表明这本书是正式版本,并且作者...

    The Ruby Programming Language

    - **Advanced Rails**:针对高级Ruby on Rails开发者的深入指南。 - **Rails Cookbook**:涵盖Ruby on Rails框架中的各种常见问题解决方案。 - **Ruby Pocket Reference**:提供Ruby语言核心特性的快速参考手册。 - ...

    The Ruby Programming Language 2008 .pdf

    - **Advanced Rails**:专注于Ruby on Rails框架的高级用法和技术细节。 - **Rails Cookbook**:类似于Ruby Cookbook,但专门针对Rails框架。 - **Ruby Pocket Reference**:一本便携式的参考手册,涵盖了Ruby语言的...

    Advanced Rails Recipes(英语清晰文字pdf+源码)

    (Ruby Recipeswas is written for Rails 1.x,this book for Rails 2.0.) Ruby on Rails continues to build up a tremendous head of steam. Fueled by significant benefits and an impressive portfolio of real...

    Ruby-服务器优化的Ruby发行版通过APTYUM实现更少内存更快速易于安装和安全补丁

    Ruby是一种强大的动态编程语言,广泛用于Web开发,尤其是在Ruby on Rails框架中。为了在服务器环境中更好地利用Ruby,一些专门针对服务器优化的发行版被开发出来,以提高性能、减少资源消耗并简化管理。"Ruby-服务器...

    Advanced.Rails(2007)].Brad.Ediger.文字版.pdf

    综上所述,《Advanced Rails》是一本深度解析Rails框架高级特性的书籍,不仅覆盖了技术层面的知识点,还提供了丰富的学习资源和支持。对于希望提升Rails技能的开发者来说,本书具有很高的参考价值。

    advanced rury on rails recipes

    从给定的文件信息来看,我们探讨的主题是“高级Ruby on Rails食谱”(Advanced Rails Recipes),这是一本旨在为专业Ruby on Rails(RoR)开发者提供深入指导的专业参考手册。尽管该书尚处于开发阶段,但其目标是...

    Advance RAils Reciples

    4. **社区资源与工具**:本书还推荐了一些与Rails相关的其他资源和工具,包括其他O’Reilly出版社的著作,如《Ajax on Rails》、《Learning Ruby》等,这些资源可以帮助读者更全面地理解和掌握Rails技术栈。...

    RailsSpace

    本书通过构建一个面向Ruby社区的社交网络平台——RailsSpace,来帮助读者掌握Ruby on Rails的核心概念和技术。本书不仅适合初学者,也适合有一定基础并希望深入了解Rails框架的开发者。 #### 二、基础知识篇 #####...

    Pragmatic.Bookshelf.Advanced.Rails.Recipes.May.2008

    这本书主要面向已经熟悉Ruby on Rails基础的开发者,旨在通过一系列实用的解决方案和技巧,提升他们在Rails框架下的开发能力。 在Rails框架中,开发者可以快速构建高效、灵活的Web应用。本书深入探讨了Rails的高级...

Global site tag (gtag.js) - Google Analytics