ruby语法基础教程

上传人:gbs****77 文档编号:9924608 上传时间:2020-04-09 格式:DOC 页数:111 大小:1.44MB
返回 下载 相关 举报
ruby语法基础教程_第1页
第1页 / 共111页
ruby语法基础教程_第2页
第2页 / 共111页
ruby语法基础教程_第3页
第3页 / 共111页
点击查看更多>>
资源描述
Ruby 语言 Grant Ren hyqryq 2006 年 11 月 24 日 2 前 言 3 目 录 Ruby 语言 1 Grant Ren 1 第一部分 Ruby 语言基础 8 第一章 Ruby 语言概述 8 1 1 Ruby 的历史 8 1 2 Ruby 名字的由来 8 1 3 Ruby 的特点 8 1 4 Ruby 和 Python 的比较 9 第二章 Ruby 编程环境 9 2 1 Ruby 的安装 9 2 1 1 在 Windows 95 98 Me XP 上安装 Ruby 9 2 1 2 在 Linux 上安装 Ruby 10 2 2 运行 Ruby 10 2 2 1 使用 Ruby 10 2 2 2 使用 FreeRIDE 和 SciTE 11 2 2 3 使用 fxri 13 2 3 Ruby irb 14 2 4 Ruby ri 15 2 5 RubyGems 15 第三章 类与对象 17 3 1 类的定义 17 3 2 对象 属性和方法 18 3 3 继承 20 3 4 特殊方法与特殊类 21 3 5 类变量与类方法 23 3 4 存取控制 23 3 6 元类 25 3 7 Ruby 的动态性 26 3 8 变量 26 3 8 1 局部变量 27 3 8 2 实例变量 27 3 8 3 类变量 27 3 8 4 全局变量 28 3 8 5 常量 28 3 8 与定义有关的操作 29 3 8 1 alias 29 3 8 2 undef 30 3 8 3 defined 31 第四章 基本类型 33 4 1 Array 33 4 2 Hash 34 4 3 Number 34 4 4 String 35 4 5 Range 36 4 4 6 Symbol 37 4 7 正则表达式 37 第五章 代码块和迭代器 38 5 1 代码块 Block 38 5 1 1 什么是代码块 38 5 1 2 代码块与对象 39 5 2 迭代器 Iterator 40 5 2 1 什么是迭代器 40 5 2 2 使用迭代器 40 5 2 3 yield 41 5 2 4 编写自己的迭代器 42 第六章 表达式 42 6 1 运算符 43 6 2 命令替换 44 6 3 赋值运算符 44 6 4 并行赋值 46 6 5 嵌套赋值 47 6 6 其他赋值 47 6 7 条件运算 47 6 8 case 表达式 48 6 9 循环 49 6 9 1 Loop 49 6 9 2 While 50 6 9 3 Until 50 6 9 4 Iterator 50 6 9 5 For In 51 6 9 6 Break Redo Next 51 6 9 7 Retry 53 第七章 方法 54 7 1 运算符重定义 55 7 2 变长参数 56 7 3 块调用 56 7 4 方法返回值 57 第八章 模块 59 8 1 名字空间 59 8 2 mixin 59 8 3 使用 mixin 60 8 3 1 Comparable 60 8 3 2 Enumerable 61 8 3 3 Singleton 62 8 4 Require load 和 include 62 第九章 异常 64 9 1 异常处理 64 9 2 定义异常类 68 9 3 catch 和 throw 68 第十章 多任务处理 69 10 1 多线程处理 69 5 10 1 1 线程创建 69 10 1 2 线程操作 70 10 1 3 线程和异常 71 10 1 4 线程调度 73 10 1 5 线程同步 73 10 2 多进程处理 79 10 2 1 进程创建 79 第十一章 基本 I O 操作 80 11 1 使用 Kernel 模块处理 I O 操作 80 11 2 文件处理 80 11 3 StringIO 81 11 4 Socket 82 第十二章 反射和对象空间 82 12 1 ObjectSpace 模块 82 12 2 察看类和对象的状态 83 12 3 动态方法调用 86 12 3 1 使用 send 方法 86 12 3 2 使用 Method 类和 UnboundMethod 类 86 12 3 3 使用 eval 方法 88 12 3 4 性能 88 12 4 Hook 和回调方法 89 12 4 1 什么是 Hook 89 12 4 2 Ruby 中的 Hook 89 11 4 2 回调方法 90 12 5 跟踪程序的运行 90 12 5 1 set trace func 90 12 5 2 trace var 91 12 5 3 caller 91 12 5 3 FILE LINE 和 SCRIPT LINES 92 第十三章 序列化和 YAML 92 13 1 序列化的概念 92 13 2 使用序列化 93 13 2 1 二进制数据保存 93 13 2 2 YAML 数据保存 93 13 3 定制序列化 94 13 3 1 二进制数据保存 94 13 3 2 YAML 数据保存 95 13 3 YAML 95 13 3 1 集合类型 96 13 3 2 单行集合类型 99 13 3 3 基本类型 99 13 3 4 块 99 13 3 5 别名和锚 Aliases and Anchors 99 13 3 6 文档 99 13 3 7 Ruby 中 YAML 的使用 99 第十四章 安全控制 100 14 1 0 级 101 6 14 1 1 级 101 14 2 2 级 101 14 3 3 级 101 14 4 4 级 101 第十五章 单元测试 101 15 1 什么是单元测试 101 15 2 Ruby 单元测试框架 101 第二部分 内置类与模块 101 第一章 内置类 102 1 1 Array 102 1 2 Bignum 102 1 3 Binding 102 1 4 Class 102 1 5 Continuation 102 1 6 Dir 104 1 7 Exception 104 1 8 FalseClass 104 1 9 File 104 1 10 File Stat 104 1 11 Fixnum 104 1 12 Float 104 1 13 Hash 104 1 14 Integer 104 1 15 IO 104 1 16 MatchData 104 1 17 Method 104 1 18 Module 104 1 19 NilClass 104 1 20 Numeric 104 1 21 Object 104 1 22 Proc 105 1 23 Process Status 105 1 24 Range 105 1 25 Regexp 105 1 26 String 105 1 27 Struct 105 1 28 Struct Tms 105 1 29 Symbol 105 1 30 Thread 105 1 31 ThreadGroup 105 1 32 Time 105 1 33 TrueClass 105 1 34 UnboundMethod 105 第二章 内置模块 106 2 1 Comparable 106 2 2 Enumerable 106 2 3 Error 106 7 2 4 FileTest 106 2 5 GC 106 2 6 Kernel 106 2 7 Marshal 106 2 8 Math 106 2 9 ObjectSpace 106 2 10 Process 106 2 11 Process GID 106 2 12 Process Sys 106 2 13 Process UID 106 2 14 Signal 106 第三部分 Ruby 语言总结 107 附录 110 1 术语对照 110 8 第一部分 Ruby 语言基础 第一章 Ruby 语言概述 1 1 Ruby 的历史 Ruby 语言的发明人是日本人松本行弘 Matsumoto Yukihiro 大家亲切的称呼他 Matz 可能会出乎大家的意料 Ruby 并不是一种近年来才诞生的语言 它的历史可以追溯到 1993 年 Ruby 之父 Matz 开始对脚本语言感兴趣 在通过一些分析和思考之后 Matz 认为脚本语言是可以变得很强大和灵活的 于是他准备把脚本语言作为他的发展方向 和很多人一样 Matz 是一个面向对象程序设计的 fans 自然而 然他想研究一种支持面向对象程序设计的脚本语言 随后的一段时间 他到网络上搜集了一些相关的资料 并且发现了 Perl 5 当时 Perl 5 还没有发布 通过一段时间了解后 Matz 发现 Perl 5 这并不是他想的东西 所以他放弃了把 Perl 当作一个面向对象的脚本语言使用的念头 随后 Matz 转向了 Python Python 是一个解 释型的 面向对象语言 但是 Matz 发现 Python 并不能完全算作 面向对象 语言 Matz 认为 Python 是面 向对象和过程化程序设计语言 Procedural Programming Language 的混合产物 Matz 希望找到的是一种比 Perl 更强大 比 Python 更面向对象的语言 但是很遗憾 这样的语言当时在地球上并不存在 于是 Matz 打 算自己设计一个全新的编程语言 1993 年 2 月 24 日是一个值得纪念的日子 在这一天 Ruby 诞生了 1995 年 12 月 Matz 推出了 Ruby 的第一个版本 Ruby 0 95 在 1996 年以前 都是 Matz 一个人在开发进行 Ruby 的开发 后来随着 Ruby 社区的渐渐形成 很多社区成员给了 Matz 许多有意义的帮助 包括提交 bug 和 patch 等 现在 Ruby 像其他开源项目一样 有自己的开发团队 任何有能力的个人或团体都可以参与 Ruby 的开发与进化 1 2 Ruby 名字的由来 首先明确一点 Ruby 并不是其他单词的缩写 受 Perl 的影响 Matz 也想用一种宝石来命名他的新语言 他使用了他的一位同事的生肖石 红宝石 后来 Matz 意识到 Ruby 这个名字十分恰当 首先 在生肖石 中 Pearl 代表六月 而 Ruby 代表七月 在字体大小上 Pearl 大小是 5pt ruby 的大小是 5 5pt 所以 Ruby 这个名字对于一种 Perl 的后续语言十分合适 1 3 Ruby 的特点 Ruby 是一种功能强大的面向对象的脚本语言 可以使用它方便快捷地进行面向对象程序设计 与 Perl 类似 而且 Ruby 具有强大的文本处理功能 使文本处理变得简单 此外还可以方便地使用 C 语言来扩展 Ruby 的功能 若您曾经 想要一种简单的面向对象的语言 或者认为 Perl 的功能虽然好用 但它的语法真让人受 不了 又或者觉得 LISP 系列语言的思想不错 但到处都是括号真让人讨厌 最起码算式应该按照通常的 样式书写 那么 Ruby 或许能让您满意 归纳起来 Ruby 有以下优点 解释型执行 方便快捷 Ruby 是解释型语言 其程序无需编译即可执行 9 语法简单 优雅 语法比较简单 类似 Algol 系语法 完全面向对象 Ruby 从一开始就被设计成纯粹的面向对象语言 因此所有东西都是对象 例如整数等基本数据类型 内置正则式引擎 适合文本处理 Ruby 支持功能强大的字符串操作和正则表达式检索功能 可以方便的对字符串进行处理 自动垃圾收集 具有垃圾回收 Garbage Collect GC 功能 能自动回收不再使用的对象 不需要用户对内存进行管理 跨平台和高度可移植性 Ruby 支持多种平台 在 Windows Unix Linux MacOS 上都可以运行 Ruby 程序的可移植性非常 好 绝大多数程序可以不加修改的在各种平台上加以运行 有优雅 完善的异常处理机制 Ruby 提供了一整套异常处理机制 可以方便优雅地处理代码处理出错的情况 拥有很多高级特性 Ruby 拥有很多高级特性 例如操作符重载 Mix ins 特殊方法等等 是用这些特性可以方便 地完成各种强大的功能 同时 由于是解释型语言 Ruby 也有下列缺点 解释型语言 所以速度较慢 静态检查比较少 1 4 Ruby 和 Python 的比较 Python 是 Ruby 的劲敌 其功力深厚 可谓 千年蛇妖 但 matz 认为 Python 的功能仍不完美 不然就 不会创造 Ruby 了 第二章 Ruby 编程环境 2 1 Ruby 的安装 Ruby 支持多种平台 包括 Windows Linux 各种类 UNIX MacOS X 等 2 1 1 在 Windows 95 98 Me XP 上安装 Ruby 对于使用 Windows 平台的用户 安装 Ruby 是相当简单直接的事情 最方便的方法是使用 One Click Ruby Installer 不知你有没有听说过 SourceForge SourceForge 是全球最大的开放源代码软件开发平台和仓库 它集成 了很多开放源代码应用程序 为软件开发提供了整套生命周期服务 在 Ruby 世界 也有一个类似的网站 那就是 Rubyforge One Click Ruby Installer 是 Rubyforge 上的一个开源项目 也是 Rubyforge 上下载量最 大的项目之一 这个项目将 Ruby 语言核心和一系列常用扩展集成到了一起 还包含支持 Ruby 的免费的 IDE 工具 FreeRIDE 和 SciTE 除了这些之外还包括帮助文档 示例代码 RubyGems 包管理器 Fox GUI 库 fxri Interactive Ruby Help make install 执行上面的命令需要 root 权限 默认安装到 usr local 下 你也可以使用 configure prefix 自定义路 径 来指定安装目录 windows 上的 ruby one click installer 默认安装了 RubyGems 但在 Linux 下我们需要手动安装 RubyGems RubyGems 是一个 Ruby 的包管理器 我们后边会讲到它 首先从 Rubyforge 下载 RubyGems 的最近版本 地址如下 http rubyforge org projects rubygems 解压 RubyGems 以后到相应目录下输入 ruby setup rb 屏幕上打印一些日志以后会告诉你安装成功 执 行 gem v 可以查看 gem 安装版本号 2 2 运行 Ruby 下面 我们将以 Windows 平台下的 Ruby 环境举例如何运行 Ruby 2 2 1 使用 Ruby 将 Hello World 作为学习计算机语言第一个学写的程序 现在已经成为一种传统 该程序最早出现 在由 Brian Kernighan 和 Dennis Ritchie 写的经典计算机程序设计教程 The C Programming Language 我们 来看看 Ruby 世界的 Hello World 在 Windows 中 打开命令行提示符窗口 在提示符上输入 Ruby 并回车 Ruby 解释器就会运行并等 候输入程序 Ruby 可执行文件应该包含在系统搜索路径内 输入下面的程序 print Hello World 然后按 Ctrl D 再按回车键 你就会看到 Ruby 执行程序的输出结果 11 你也可以先将代码保存为文件 然后使用再 Ruby 解释器执行 2 2 2 使用 FreeRIDE 和 SciTE FreeRIDE 是一个支持 Ruby 语言的免费 IDE 环境 FreeRIDE 本身就是使用 Ruby 语言开发 它也是 12 Rubyforge 上的重要项目之一 可以使用 FreeRIDE 来编写调试和执行 Ruby 代码 FreeRIDE 内置了交互式变成环境和 Ruby 语言在线 帮助 功能十分强大 Scintilla 是一个免费的源代码编辑控件 它完全开放源代码 并允许用户自由地用于开源软件或是商业 软件中 SciTE 是用这个控件开发了一个编辑软件 在 One Click Ruby Installer 中 SciTE 集成了 Ruby 语言支持 使用起来非常方便 相比 FreeRIDE 它的特点就是使用简单 13 2 2 3 使用 fxri Fxri 是一个 Ruby 交互帮助和控制台工具 它不仅可作为语言的在线帮助 而且可以用作交互式 Ruby 解 释器来执行程序 对于学习 Ruby 语言 fxri 是一个非常方便的帮手 不知你有没有听说过 Fox ToolKit 它是相当轻巧的开放源代码的图形库 FXRuby 是 RubyForge 上的一个 项目 提供了 Ruby 语言使用 Fox ToolKit 的接口 而 Fxri 正是基于 FXRuby 开发 Fxri 同样是 RubyForge 上的 项目 这样你应该可以猜到 Fxri 名字的由来 14 Fxri 同时集成了 Ruby irb 和 Ruby ri 的功能 有了它 你可以抛开 Ruby irb Ruby ri 了 但如果你用的 不是 Windows 系统的话 算我没说 2 3 Ruby irb Ruby irb 是交互式 Ruby Interactive Ruby 的简称 用来从标准输入读入并执行 Ruby 代码的工具 像 一个 shell 使用命令 irb 进入交互式模式 然后可以象输入命令行命令一样输入 Ruby 代码 代码执行的结果会 立刻显示 15 2 4 Ruby ri 和 Perl 一样 Ruby 也设计了嵌入式文档 ruby ri 就是查看文档的工具 Ruby ri 的执行命令为 ri 例如你可以通过 ri String new 来查询 String 类的 new 方法 2 5 RubyGems RubyGems 是 Ruby 社区流行的包管理工具 在以前如果要下载一个 Ruby 扩展或者应用程序的话 你 16 需要先下载相应的 zip 包 然后解压缩 再将应用或者扩展安装到 Ruby 对应的目录中 但是有了 RubyGems 所有这些麻烦都没有了 你只需要一条命令就可以从远程服务器上下载相应的包 如果相应的应 用包含其他扩展 RubyGems 会提示你从远程安装所依赖的扩展 安装后 RubyGems 会运行相应的程序生 成 rdoc 帮助文档 当然你也可以将软件包下载到本地运行 RubyGems 本地安装命令 统一化的管理带来的好处就是简单 有了 RubyGems 包管理器 Ruby 应用的安装将变得前所未见的容 易 RubyGems 是 Rubyforge 下载量最大的项目之一 现在 Ruby 社区的应用都在朝着 RubyGems 的方向发 展 RubyGems 也将成为 Ruby 事实上的包管理器标准 RubyGems 包管理器的可执行命令是 gem gem 命令包含很多子命令和相应的选项 例如 gem h help 显示命令帮助 gem v version 显示 Gems 的版本号 17 第三章 类与对象 Ruby 是一种真正的面向对象程序设计语言 面向对象指以对象为中心的理论体系 封装 Encapsulation 将内部结构和算法隐藏起来 以确保只有特定的过程 也叫方法 才能直接操作数据 其结果是不能从外 部直接使用数据构造 同时一旦内部构造发生变化也不会对外界造成不良影响 这种隔离方法就叫做封装 继承 多态 Polymorphism 根据对象的不同选择合适的操作 在 Ruby 中的实现方法是 根据被调的对象的不同来选择不同的方法 虽然有很多语言都宣称自己是面向对象的 但是他们往往对面向对象的解释都一样 大多是以自己特 有的方式来解释什么是面向对象 而在实际情况中 这些面向对象语言又采用了很多非面向对象的做法 以 Java 为例 如果你想取一个数字取绝对值 java 的做法是 int num Math abs 99 也就是将一个数值传递给 Math 类的一个静态函数 abs 处理 为什么这么做 因为在 java 中 数值 是基本类型不是类 而在 Ruby 中 任何事物都是对象 也就是说 数字 99 就是对象 取绝对值这样的操作应该属于数 字本身 所以 Ruby 的做法就是 c 99 abs 在 Ruby 中 你所操作的一切都是对象 操作的结果也是对象 3 1 类的定义 类是对具有同样属性和同样行为的对象的抽象 Ruby 中类的声明使用 class 关键字 定义类的语法如下 class ClassName def method name variables some code end end 类的定义要在 class end 之间 在上面的格式中 ClassName 是类名 类名必须以大写字母开始 也 就是说类名要是个常量 看下面的例子 class Person def initialize name gender age name name gender gender age age end end 若某个类已经被定义过 此时又用相同的类名进行类定义的话 就意味着对原有的类的定义进行追加 class Test def meth1 puts This is meth1 end end 18 class Test def meth2 puts This is meth2 end end 在 Test 类中 原有 meth1 方法 我们又追加了 meth2 方法 这时候 对于 Test 类的对象 meth1 和 meth2 同样可用 3 2 对象 属性和方法 类在实例化后生成对象 在强调对象归属于某类时 有时候我们也使用实例对象一词 方法 Method 是对对象进行的操作 操作对象 被调 以 self 来表示 在 Ruby 中 除去内部类的对象 以外 通常对象的构造都是动态确定的 某对象的性质由其内部定义的方法所决定 看下面的例子 我们使用 new 方法构造一个新的对象 class Person def initialize name gender age name name gender gender age age end end people Person new Tom male 15 我们可以使用 Person new 方法来创建一个 Person 类的实例对象 以 打头的变量是实例变量 他 们从属于某一实例对象 Ruby 中实例变量的命名规则是变量名以 开始 您只能在方法内部使用它 initialize 方法使对象变为 就绪 状态 initialize 方法是一个特殊的方法 这个方法在构造 实例对象时会被自动调用 对实例进行初始化操作时 需要重定义 initialize 方法 类方法 new 的默认的行为就是对新生成的 实例执行 initialize 方法 传给 new 方法的参数会被原封不动地传给 initialize 方法 另外 若带 块调用时 该块会被传给 initialize 方法 因此 不必对 new 方法进行重定义 在 Ruby 中 只有方法可以操作实例变量 因此可以说 Ruby 中的封装是强制性的 在对象外部不可以 直接访问 只能通过接口方法访问 class Person def name name end def gender gender end def age age end end people Person new Tom male 15 puts people name puts people gender puts people age 输出结果为 Tom male 15 19 在 Ruby 中 一个对象的内部属性都是私有的 上面的代码中 我们定义了方法 name gender age 三 个方法用来访问 Person 类实例对象的实例变量 注意 name gender age 访问只能读取相应实例变量 而 不能改变它们的值 我们也可以用成员变量只读控制符 attr reader 来达到同样的效果 class Person attr reader name gender age end 类似地 我们可以定义方法去改变成员变量的值 class Person def name name name name end def gender gender gender gender end def age age age age end end people Person new Tom male 15 people name Henry people gender male people age 25 也可以用成员变量写控制符 attr writer 来达到同样的效果 class Person attr writer name gender age end 我们也可以使用 attr accessor 来说明成员变量既可以读 也可以写 class Person attr accessor name gender age end 也可以使用 attr 控制符来控制变量是否可读写 attr 只能带一个符号参数 第二个参数是一个 bool 参数 用于指示是否为符号参数产生写方法 它的默认值是 false 只产生读方法 不产生写方法 class Person attr name true 读写 attr gender true 读写 attr age true 读写 attr id false 只读 end 注意 attr reader attr writer attr accessor 和 attr 不是语言的关键字 而是 Module 模块的方法 class Test attr accessor value end puts Test instance methods Test superclass public methods 执行结果为 value 20 value 上面代码中 我们使用 Test instance methods 得到 Test 类所有的实例方法 使用 Test superclass public methods 得到 Test 父类所有的实例方法 然后相减就得到 Test 类不包 含父类的所有的实例方法 由于 instance methods 方法返回值为一个 Array 所以我们作差值运算 Array 的具体操作后面 章节会讲到 也可以重定义方法 重定义一个方法时 新的定义会覆盖原有的定义 下面的例子重定义类中的方法 meth1 class Test def meth1 puts This is meth1 end end a Test new a meth1 class Test def meth1 puts This is new meth1 end end a meth1 执行结果为 This is meth1 This is new meth1 重定义同一个类时 意味着对原有定义进行补充 不会覆盖原来的定义 而重定义方法时 则会覆盖 原有定义 我们可以使用 self 标识本身 self 和 Java 中的 this 有些类似 代表当前对象 class Person def initialize name gender age name name gender gender age age end def other self age other age end end 方法通常意思为比较 返回值为 1 0 或 1 分别表示小于 等于和大于 3 3 继承 Ruby 继承的语法很简单 使用 即可 class Student Person def initialize name gender age school name name gender gender age age 21 school school end end Ruby 语言只支持单继承 每一个类都只能有一个直接父类 这样避免了多继承的复杂度 但同时 Ruby 提供了 mixin 的机制可以用来实现多继承 可以使用 super 关键字调用对象父类的方法 当 super 省略参数时 将使用当前方法的参数来进行 调用 class Base def meth info puts This is Base info end end class Derived Base def meth info puts This is derived info super end end obj1 Derived new obj1 meth test 执行结果为 This is derived test This is Base test 如果传入的参数被修改再调用 super 的话 那么将会使用 使用修改后的值 class Base def meth info puts This is Base info end end class Derived Base def meth info puts This is derived info info over super end end obj1 Derived new obj1 meth test 执行结果为 This is derived test This is Base over 3 4 特殊方法与特殊类 特殊方法是指某实例所特有的方法 一个对象有哪些行为由对向所属的类决定 但是有时候 一些特 殊的对象有何其他对象不一样的行为 在多数程序设计语言中 例如 C 和 Java 我们必须定义一个新类 但在 Ruby 中 我们可以定义只从属于某个特定对象的方法 这种方法我们成为特殊方法 Singleton Method 22 class SingletonTest def info puts This is This is SingletonTest method end end obj1 SingletonTest new obj2 SingletonTest new def obj2 info puts This is obj2 end obj1 info obj2 info 执行结果为 This is This is SingletonTest method This is obj2 有时候 我们需要给一个对象定义一系列的特殊方法 如果按照前面的方法 那么只能一个一个定义 def obj2 singleton method1 end def obj2 singleton method2 end def obj2 singleton method3 end def obj2 singleton methodn end 这样做非常繁复麻烦 而且无法给出一个统一的概念模型 因此 Ruby 提供了另外一种方法 class obj end obj 是一个具体的对象实例 class 代表它的特殊类 class SingletonTest def meth1 puts This is meth1 end def meth2 puts This is meth2 end end obj1 SingletonTest new obj2 SingletonTest new class 22429840 puts Person object id 22429960 没错 类也是对象 这是 Ruby 和 C Java 的一个显著不同 在 C Java 中 类仅仅是一个数据 抽象 并没有类也是对象这样的概念 而在 Ruby 中存在着元类的概念 类也是对象 所有类都是元类的实 例对象 和 C Java 相比 Ruby 的面向对象程度更高 可以看到 类对象和实例对象一样有自己的 ojbect id 你可以象调用一个实例对象的方法一样去用 它去调用类方法 所有类对象的类是 Class 类 Oject 类是所有类的基类 irb main 003 0 Object class Class irb main 004 0 Object superclass nil 这样 我们可以从另一个角度去理解类变量与类方法 类变量就是一个类对象的实例变量 类方法就 是指一个类对象类的特殊方法 类方法具体可分为两种 第一种是在所有的类的父类 Class 中定义的 且被所有的类所共享的方法 第 二种是各个类所特有的特殊方法 类方法中的 self 指的是类本身 这点需要牢记 这样我们可以使用多种方式定义类方法 class Test 定义类方法方式 1 def Test meth1 end 定义类方法方式 2 def self meth2 end 定义类方法方式 3 class Test 26 def meth3 end end 定义类方法方式 4 class self def meth4 end end end 3 7 Ruby 的动态性 可以重新定义同一个方法 class RedefTest def meth puts This is meth end end obj1 RedefTest new obj1 meth class RedefTest def meth puts This is new meth end end obj1 meth 执行结果为 This is meth This is new meth 可以使用 undef method 取消一个方法的定义 class UndefTest def meth puts This is meth end end obj1 UndefTest new obj1 meth class UndefTest undef method meth end obj1 meth 执行结果为 This is meth test rb 14 undefined method meth for NoMethodError 27 3 8 变量 变量名长度只受内存大小的限制 可以通过区分 Ruby 变量名的首字符来区分它是局部变量 实例变 量 类变量 全局变量还是常量 通常情况下 变量名的第二位字符以后是数字 字母或下划线 但有的 内部变量名比较特殊 如 3 8 1 局部变量 局部变量以小写字母或下划线开始 num 1 foo 局部变量的作用域起始于声明处 结束于该声明所在的块 方法定义 类 模块定义的结尾 2 times p defined num num 10 p num 输出为 nil 10 nil 10 即使声明部分未被解释器执行仍有效 因为已经经过解释器的处理 v 1 if false p defined v p v 输出为 local variable nil 但若块已经变成过程对象的话 则局部变量将一直持续到该过程对象终结为止 若多个过程对象 引用同一个作用域的话 局部变量将被这些对象所共享 to do 例子 3 8 2 实例变量 以 开始的变量是实例变量 实例变量属于特定的对象 class Person def initialize name gender age name name gender gender age age end end 28 上面的例子中 name gender age 都是实例变量 可以在类或子类的方法中引用实例变量 若引用尚未被初始化的实例变量的话 其值为 nil 3 8 3 类变量 以 开始的变量是类变量 类变量在类的定义中定义 可以在类的特殊方法 实例方法等 处对类变量进行赋值和引用 类变量被类 类的子类和他们的实例对象共享 class Person number 0 使用前必须有初值 def initialize name gender age name name gender gender age age number 1 end end 类变量是私有的 在类外无法直接访问 你只能通过实例方法和类方法去访问它 可以把 类变量看作一种被类 子类以及它们的实例所共享的全局变量 模块中定义的类变量 模块变量 被所有包含该模块的类所共享 module TestModule foo 10 end class Klass include Foo p foo 1 11 end class Base include Foo p foo 2 12 end 3 8 4 全局变量 以 开始的变量是全局变量 全局变量可以在程序的任何地方加以引用 全局变量无需变量声明 引用 尚未初始化的全局变量时 其值为 nil Ruby 运行时环境预定义了一系列的全局变量 有关预定义的全局变量的信息 请参见附表 3 8 5 常量 常量以大写字母开始 常数的定义和初始化由赋值过程完成 PI 3 14 E 2 71 若对已定义的常数进行赋值的话 会出现警告信息 若引用未定义的常数会引发 NameError 异常 PI 3 14 obj1 2 PI 10 PI 3 1415 warning already initialized constant PI obj2 Foo uninitialized constant Foo NameError 29 常量可以定义在类和模块中 不能定义在方法中 class Meth PI 3 14 OK end def circle area arg PI 3 14 ERROR PI arg arg end 若想在外部访问类或模块中的常数时 要使用 操作符 class Meth PI 3 14 end def circle area arg Math PI arg arg end 在类定义表达式生成类对象的同时 还会将类对象赋值给一个与该类同名的常数 引用类名也就是引 用该常数 class Test end p Test class Class p Test test 若想访问 Object 类中的常数 顶层的常数 时 也需要也使用 操作符 但操作符左边为空 3 8 与定义有关的操作 3 8 1 alias Alias 关键字给方法或全局变量添加别名 可以给方法名指定一个标识符或 Symbol 作为别名 给方法 添加别名时 别名方法将和此刻的原始方法绑定 此后即使重新定义了原始方法 别名方法仍然保持着重 定义前的老方法的特性 若改变了某方法的内容后 又想使用修改前的方法时 别名会很有用 也可以使 用 Module alias method 给方法添加别名 定义 meth 方法 def meth puts This is meth end 设定别名 alias orig meth meth 重定义 foo def meth puts This is new meth end p meth 30 执行结果为 This is new meth nil 给全局变量设定别名意味两个名称指向同一个全局变量 当你向一个赋值时 另一个也会被改变 abc 1 alias xyz abc xyz 2 p abc xyz 2 2 但是不能给正则表达式中的变量 1 2 等添加别名 另外 有些全局变量对于解释器来说是举足轻重 的 若重新定义它们的话 有时会影响解释器的正常工作 3 8 2 undef undef 用来取消一个方法的定义 也可以使用 Module undef method 方法取消方法的定义 undef 会取 消方法名和方法定义之间的关系 即使超类中有同名方法 调用时也会引发异常 class Base def meth puts This is Base meth end end class Derived Base def meth puts This is Derived meth end end class Test1 Derived def meth puts This is Test1 meth end undef method meth end obj1 Test1 new obj1 meth 执行结果为 Tes1 rb 22 undefined method meth for NoMethodError 而 Module remove method 方法只负责取消当前类中方法名和方法定义之间的关系 父类的同名方 法仍可调用 这点差别非常重要 class Base def meth puts This is Base meth end end class Derived Base def meth puts This is Derived meth end end 31 class Test2 nil defined true true defined global variable defined Array constant defined Math PI constant defined num 0 assignment defined 100 expression defined 100 times method 虽然 defined 看起来像一个方法 实际上是 Ruby 语法中的操作符 因此不会对参数进行计算 因此 下面的表达式并不会输出 abc defined print abc n 如果是方法未定义 或方法使用 undef 或 Module remove method 取消了原有定义 defined 都 将返回 nil 注意如果一个方法以大写字母开头 使用 defined 判断时需要在方法名后添加 时 否则方法名会被 当做常数处理 def Foo arg end p defined Foo nil p defined Foo method Foo 1 p defined Foo constant 还可以使用下列特殊用法 判断 yield 是否可用 defined yield 若 yield 调用可用 则返回真 具体返回值为字符串 yield 它的作用同 block given 一样 可以判断能 否以带块方式来调用某方法 32 class Base def foo puts defined yield end end a Base new a foo a foo 执行结果为 nil yield 判断 super 是否可用 defined super 若 super 可被调用 则返回真 具体返回值为字符串 super class Base def foo end end class Derived assignment p a nil 在正则表达式中使用 foo p defined Thread stop bthr Thread new Thread current name Thread B Thread stop cthr Thread new Thread current name Thread C Thread stop Thread list each x puts x inspect x name 可以看到 把线程作为一个 Hash 表 使用 和 方法 我们实现了线程之间的数据共享 10 1 3 线程和异常 当一个线程运行时如果发生异常会怎样 这和 abort on exception 标志和解释器的 debug 标志有关 abort on exception 默认被设置为 false 这时候发生异常的那个线程会被杀死 其他线程继续运行 只有当 你对发生异常的线程使用 join 操作时你才会察觉到有异常发生 a Thread new raise Error A b Thread new puts Thead B c Thread new puts Thead C b join c join 72 执行结果为 Thead B Thead C a Thread new raise Error A b Thread new puts Thead B c Thread new puts Thead C a join b join c join 执行结果为 Thead B Thead C test rb 1 Error A RuntimeError from test rb 4 in join from test rb 4 我们也可以在使用 join 时捕获这个异常 threads threads 0 Thread new raise Error A threads 1 Thread new puts Thead B threads 2 Thread new puts Thead C threads each do t begin t join rescue RuntimeError e puts e message end end 执行结果为 Thead B Thead C Error A 然而设置了 abort on exception 标志或者使用 d 打开了 debug 开关 如果抛出了未被捕获的异 常 程序将结束 所有的线程都将被终止 Thread abort on exception true threads threads 0 Thread new raise Error A threads 1 Thread new puts Thead B threads 2 Thread new puts Thead C threads each do t begin t join rescue RuntimeError e puts e message end end 执行结果为 test rb 3 Error A RuntimeError from test rb 3 in initialize from test rb 3 in new from test rb 3 73 10 1 4 线程调度 Thread 类提供了一系列的方法用来控制线程调度 Thread run 方法用来运行一个线程 Thread stop 方法停止线程的运行 Thread pass 方法取消运行当前线程 继续其他线程的运行 Thread join 方法将当前线程挂起直 到指定线程运行结束 Thread value 方法和 Thread join 类似 将线程挂起直到指定线程运行结束并 取得返回值 a Thread new print a Thread pass print b Thread pass print c b Thread new print x Thread pass print y Thread pass print z a join b join 执行结果为 axbycz 上面的例子中 我们使用 pass 方法放弃当前的控制权 继续下一个线程的运行 a Thread new print a Thread stop print c Thread pass print b a run a join 执行结果为 abc 上面的例子中 线程 a 开始运行后先输出 a 然后使用 stop 方法停止运行 主线程使用 pass 方 法放弃放弃当前的控制权 保证 a 最先输出 然后我们使用 run 方法重新运行线程 a 所以输出结果为 abc a Thread new 4 5 puts a value 执行结果为 9 上面的例子中 我们是用 value 方法等待线程结束并打印出线程执行的返回值 线程执行的返回值就 是线程执行的最后一个语句的值 10 1 5 线程同步 因为线程共享内存空间 所以可以使用普通的变量完成线程间的数据交换工作 如果有多个线程同时 工作 请确保它们之间不存在互相等待以到达某一点或完成的情况 如果操作错误 可能会导致死锁状态 74 两个线程都无法完成 因为它们都在相互等待 使用线程的另一个常见问题是竞争状态 如果一个线程正在将数据写入文件 而另一个线程正在从该 文件中读取数据 如果读取线程快于写入线程 则将返回无法预料的结果 这种情况称为竞争状态 有时候在运行程序中 一些你认为不需要同步的地方也会出现资源同
展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 办公文档 > 解决方案


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!