`
wangdeshui
  • 浏览: 255752 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

一步一步学Ruby(十七):Ruby动态特性

阅读更多

Ruby中的一切都是动态的,例如,我们可以在程序运行时,动态的添加方法,类等。前面我们已经看到了Ruby的动态特性,例如:给单个对象添加方法,重新打开类等。

如果熟悉Rails,就知道ActiveRecord提供基于数据库表的字段名的方法。每一个字段都有一个方法,这个就依赖于Ruby的动态特性。

一、单例类的位置

我们可以为一个对象定义只属于自己的方法
obj=Object.new
def obj.say
    puts "Hello World"
end
obj.say  #输出 Hello World
那么单例方法定义在哪里呢?Ruby把单例方法定义在单例类(singleton class)中.每一个对象实际上都有两个类:
  • 多个实例共享的类
  • 单例类

对象调用的方法就是定义在这两个类中的方法,以及祖先类和混含模块中的方法,对象可以调用它所属的类的实例方法,也可以调用单例类中的方法。单例类是匿名的,他们是类对象的实例(Class类的实例),但他们是自动生成且没有名字

str="Hello World"
class<<str
   def bye
      self+", bye"
   end
end
puts str.bye

输出 "Hello World, bye"

在方法查找上,单例方法是最先找到的。

二、eval方法

这个和其它很多语言一样,具有在运行时执行以字符串形式保存代码的的功能。

1.直接执行代码

image

2. 运行时提供方法名的例子
print "Greeting Method:"
m=gets.chomp
eval("def #{m};puts 'Hello'; end")
eval(m)
输出:Hello
如果输入hi, eval求职的字符串是 def hi; puts 'Hello'; end
三、eval的危险性
eval很强大,但是它也潜在着危险,这个有点像sql注入
假如,上面我们输入的不是hi而是下面的内容
hi; end; system("rm -rf /*"); #

eval求值以后是这样的

def hi; end; system("rm -rf /*"); # puts  'Hello'; end
求值的结果是:#后面的所有内容会被作为注释忽略掉。使用system命令试图删除系统所有文件
Ruby有一个全局变量$SAFE(取值范围是0到4)、以获取对如非法写文件这一类危险的防护。
四、instance_eval
该方法把self变为instance_eval调用的接收者,对字符串或代码块进行求职
p self
a=[]
a.instance_eval(p self)
输出:
main
[]
instance_eval常用于访问其它对象的私有数据,特别是实例变量
class C
  def initialize
    @a=1
  end
end
c=C.new
c.instance_eval {puts @a}
 
五、class_eval
class_eval可进入类定义体中
c=Class.new
c.class_eval do
  def some_method
    puts "created in class_eval"
  end
end

c=c.new
c.some_method
利用class_eval可以访问外围作用域的变量。
var="test variable"
class C
  puts var
end
C.class_eval {puts var}
变量var在标准的类定义体的作用域之外,但是在class_eval的代码块的作用域之内
image
当在class_eval的块中定义一个实例方法时,又有不同
var="test"
class C
end
C.class_eval {def hi; puts var; end}
c.new.hi
# undefined local variable or method `c' for main:Object (NameError)
但我们可以使用另外一种方法
C.class_eval {define_method("hi"){ puts var}}
六、Proc对象
pr=Proc.new {puts "Hello from inside of proc block"}
pr.call
#输出: Hello from inside of proc block
1、做为闭包的Proc对象
Proc对象随身携带了它的上下文,下面上下文包含一个变量a,该变量被赋值为一个特殊的字符串保存在Proc对象中。像这样带着产生它的上下文信息的
一段代码被称为闭包。产生一个闭包就像是打包一件行李:任何时候打开行李,都包含打包进去的东西,在打开一个闭包时(通过调用它),它包含产生
它的时候你放进去的东西。
def call_proc(pr)
  a="Jack"
  puts a
  pr.call
end
a="Tom"
pr=Proc.new {puts a}
pr.call
call_proc(pr)
#输出: Tom
#      Jack
#      Tom
2. Proc对象的参数
产生Proc对象时所提供的代码块可以接收参数
pr=Proc.new {|x| puts "#{x} is better man"}
pr.call("Jack")
输出:Jack is better man
七、匿名函数(lambda)
lam=lambda {puts "Hello World"}
lam.call
输出: Hello World
lambda不是Lambda类的对象,他们是Proc类的对象
lam.class
输出: Proc

和所有的Proc对象一样,lambda是闭包;他们随身携带了生成他们的局部的上下文环境

lambda生成的Proc对象和用Proc.new生成的对象之间的差别与return有关,lambda中的return从lambda返回,而Proc中的return从外围方法返回

def test_return
  l=lambda {return}
  l.call
  puts "I am here"
  p=Proc.new {return}
  p.call
  puts "bye"
end
test_return
输出: "I am here"
八、再论代码块
可以在方法中吧代码块转换成Proc对象,可以通过参数中最后一个变量,且必须&开头来捕获代码块
def say_block(&block)
  block.call
end
say_block {puts "How are you?"}
#output: how are you?
def test_block(x,y,  &block)
  puts x+y
  block.call
end
test_block(1,2) {puts "Hi"}
#output: 3 
#        Hi
也可以将Proc对象或lambda转换为代码块
def say_block(&block)
  block.call
end

lam=lambda {puts "Hello world"}
say_block(&lam)
#output: Hello world

本文作者:王德水
未经同意,禁止转载
分享到:
评论

相关推荐

    .一步一步学RUBY

    松本行弘在设计Ruby时,融合了多种他所喜爱的语言特性,包括**Perl**、**Smalltalk**、**Eiffel**、**Ada**和**Lisp**,从而创造出一种结合了函数式和过程式编程特性的独特语言。他的目标是使Ruby既自然又强大,即使...

    Ruby on Rails Guides v2 - Ruby on Rails 4.2.5

    ### Ruby on Rails Guides v2 - Ruby on Rails 4.2.5 #### 一、重要概念及基础假设 - **重要概念**:本指南旨在帮助读者深入理解Ruby on Rails(以下简称Rails)4.2.5版本的核心功能与最佳实践。 - **基础假设**:...

    from java to ruby -things every manager should know

    - **Ruby**:相比之下,Ruby 是一种动态类型的脚本语言,它的语法更加灵活,支持多种编程范式(包括面向对象和函数式编程)。Ruby 代码通常更简洁、易于阅读。 2. **生产力与开发效率**: - **Java**:虽然 Java ...

    ruby-jogging:ruby 的每日提交

    4. **闭包和上下文**:理解块、Proc和Lambda如何捕获并保留其定义时的上下文,是掌握Ruby高级特性的重要一步。 5. **元编程**:Ruby允许在运行时修改自身,这被称为元编程。例如,你可以动态添加方法、修改类的行为...

    ruby-chess:用Ruby创建的国际象棋游戏

    Ruby是一种面向对象的、动态类型的脚本语言,以其简洁明了的语法和强大的元编程能力著称,这使得它成为开发复杂逻辑应用的理想选择,比如棋类游戏。 在Ruby-chess项目中,每个棋子被表示为一个对象,它们有自己的...

    ruby开发的基本流程.doc

    Ruby是一种动态的、面向对象的解释型编程语言,因其简洁易读的语法和强大的库支持而在Web开发领域中备受青睐。开发Ruby应用的第一步是搭建合适的开发环境。推荐使用macOS或Linux作为首选操作系统,因为这些系统通常...

    Refactoring Ruby

    - **利用元编程**:利用 Ruby 的元编程能力,如模块混合(mixins)、动态方法定义等特性进行重构。 - **利用动态类型**:通过动态地修改类和对象来优化代码结构。 - **利用代码块和迭代器**:利用 Ruby 强大的迭代器...

    linux版 ruby-2.3.0

    Ruby是一种面向对象、动态类型的编程语言,由日本的松本行弘在1995年设计并开发。它强调简洁、优雅的语法,注重程序员的生产力,并提供了丰富的库和工具支持。Ruby-2.3.0是Ruby的一个版本,发布于2016年,带来了许多...

    Ruby语言入门教程v1.0

    从早期的机器语言到汇编语言,再到高级语言如C、C++、Java,以及动态语言如Python、Ruby,每一步都标志着计算机科学的进步。了解这一历史脉络有助于学习者更好地把握Ruby语言在当前编程生态中的位置及其独特价值。 ...

    Ruby编辑器scite F5可以运行

    Ruby是一种面向对象、动态类型的编程语言,以其简洁的语法和强大的功能深受开发者喜爱。Scite,全称SciTE( Scientific ...在深入学习Ruby编程的同时,掌握Scite的各种特性和设置,无疑会成为提升开发技能的重要一步。

    Ruby语言入门教程

    Ruby作为一种灵活且强大的编程语言,具有以下显著特性: - **面向对象**:一切皆对象,包括基本的数据类型。 - **动态类型**:无需提前声明变量类型,增加了语言的灵活性。 - **简洁的语法**:Ruby的语法简洁明了,...

    ruby-2.5.0.tar.gz

    Ruby-2.5.0是Ruby编程语言的一个版本,它在2018年发布,带来了许多性能优化和新特性。这个`.tar.gz`文件是一个压缩包,它包含Ruby 2.5.0的所有源代码文件,适用于在CentOS 6.5上安装Redmine时使用。Redmine是一款...

    ruby-2.25.tar.gz

    在Ruby-2.2.5这个版本中,有以下几个重要的改进和特性: - **性能提升**:相比于之前的版本,Ruby-2.2.5在运行速度上有所优化,提高了程序执行效率。 - **更好的垃圾回收机制**:改进了垃圾回收算法,减少了内存...

    适合Ruby 1.9.1的Ruby-FCGI源码包

    3. 运行`ruby extconf.rb`来生成Makefile,这一步会根据当前的Ruby环境配置编译选项。 4. 接着运行`make`来编译C扩展。 5. 最后,运行`sudo make install`将编译好的扩展安装到Ruby的扩展目录。 在使用Ruby-FCGI时...

    开放Ruby+watir 自动化测试工具介绍+安装说明

    Ruby是一种高级、动态的、面向对象的编程语言,它的设计理念在于提供简单且高效的编程体验。Ruby以其简洁的语法和强大的面向对象特性而受到开发者的喜爱。作为解释型语言,Ruby代码可以直接执行,无需预编译步骤,这...

    24_ruby_algorithm_

    标题 "24_ruby_algorithm_" 暗示我们要讨论的是使用 Ruby 编程语言实现解决数学游戏“24点”的算法。在这个经典游戏中,玩家...通过对 `24.rb` 文件的分析和学习,开发者可以加深对 Ruby 语言特性和算法设计的理解。

    ruby数组

    Ruby是一种面向对象的编程语言,以其简洁和强大的语法特性而受到开发者喜爱。在Ruby中,数组是一种非常重要的数据结构,用于存储一系列有序的元素,这些元素可以是任意类型,包括整数、浮点数、字符串、布尔值甚至是...

    ruby 知识总结

    Ruby是一种动态类型、面向对象的脚本语言,其语法简洁优雅,特别适合快速开发和原型设计。在这篇知识总结中,我们将深入探讨Ruby中的线程同步和闭包(包括Blocks、Procs、Lambdas和Methods)。 首先,让我们关注...

    chessagain:通过国际象棋演练刷我的Ruby

    通过这个项目,开发者不仅能深入理解Ruby的基本语法和特性,还能锻炼到问题解决、算法设计以及代码组织等高级编程技巧。在实际操作中,你可能还需要学习如何使用版本控制工具如Git,以及如何编写清晰的文档,以便...

    基于Ruby的分布式服务系统的设计.pdf

    Ruby中的所有基本类型、代码块、函数、类和模块都是对象,而且类是开放的,支持动态添加、更新、删除成员。Ruby的singleton特性使得对象能够拥有独特的功能,便于控制服务类型;Ruby还支持mix_in模块,使得系统设计...

Global site tag (gtag.js) - Google Analytics