参考教材:《Ruby基础教程》 第5版 —— [日]高桥征义 后藤裕藏著
第一部分
第一章:Ruby初探
- Ruby官网:http://www.ruby-lang.org/zh_cn/
- Ruby命令的执行方法:
- 命令行工具中:
ruby <filename>.rb - irb:交互式Ruby运行环境(使用时需要注意中文的问题)
- 命令行工具中:
- 字符串
-
''和""的区别:在表示一般字符串时,两者没有区别,不过当字符串内容含有\n \s等转义字符时,''中的字符不会经过转义。 -
puts函数和print函数还有p函数的区别:-
puts函数会原封不动并将转义字符进行转义后输出,而且末尾在每次输出完一个参数后自动加个换行 -
print函数:puts函数的不加换行版 -
p函数: 对内容不进行转义直接输出,该函数一般只给编程者使用
-
-
- 方法的调用
-
function_name(arg1, arg2...):带括号的参数调用,适合参数较多的情况 -
function_name arg1, arg2...:不带括号的调用,调用格式简洁明了,没有固定的要求,合适的地方用合适的方法才是最好的
-
- 注释
- 单行注释法:
# 这里是注释 - 多行注释法:
=begin 这里是注释 =end
- 单行注释法:
- 控制语句:基本四类顺序,条件,循环和异常,具体下面再写。
第二章:便利的对象
- 数组:
[] - 散列:在Java和C++中称为Map,在Python和JavaScript中称为字典,大差不差,key-value形式的键值对。
- 正则表达式:基本格式为
/模式/ =~ 希望匹配的字符串序列(=~符号的使用)
第三章:创建命令
-
ARGV系统变量的使用,例如:ruby print_argv.rb 1st, 2nd那么ARGV[0] == "1st"; ARGV[1] == "2nd"以此类推 - 文件的读取:开-读(写)-关三个基本处理流程,例如:
哈哈,就是这么简单,不像有的语言那么复杂。说你呢C和Java。filename = ARGV[0] text = File.open(filename).read puts text text.close - 引用其他文件:
require 希望使用的库名/require_relative 希望使用的库名,前者用来引用已存在的库,后者用来引用相对路径下的库。
第二部分
第四章:对象,变量和常量
对象:数值对象,字符串对象,数组散列对象,正则表达式对象,事件对象,文件对象,符号对象,范围对象和异常对象等等等等等等...
类:对象的抽象层面(一般的面向对象思想哈哈哈)
-
变量(在Ruby中变量有点特殊,小心作用域。此外,变量的命名方法和上下文共同决定了变量种类)
- 局部变量(local variable):英文小写字母或_开头
name = "哈哈哈" - 全局变量(global variable):使用美元符
$开头$name = "哈哈哈" - 实例变量(instance variable):以
@开头@name = "哈哈哈" - 类变量(class variable):以
@@开头@@name = "哈哈哈" - 实际上还有预定义变量和伪变量
- 局部变量(local variable):英文小写字母或_开头
常量:使用大写英文字母开头,例如
NAME = "哈哈哈大写版"-
保留字(一个大大的表)
__LINE____ENCODING____FILE__BEGINENDaliasandbeginbreakcaseclassdefdefined?doelseelsifendensurefalseforifinmodulenextnilnotorredorescueretryreturnselfsuperthentrueundefunlessuntilwhenwhileyield`` `` `` `` 多重赋值:就是
a, b = 1, 2,可以有灵活的编程方法,例如a, b = b, a-
命名方法:驼峰表示法或者下划线表示法,都可以。不过约定俗成的是:
Ruby中的变量名和方法名要用下划线表示法,类名和模块名要用后者。
第五章:条件判断
主要有三种语句:
if, unless, case-
真假值:
条目 判断依据 真 false和nil以外的所有对象假 false和nil 特别的
unless: 正好和if相对===和case语句:case语句在判断的时候,实际上用的是===运算符。但是===可以匹配更广泛的等于,例如正则表达式是否
匹配,右边的对象是否属于左边的类。当然,对于一般的数值或字符串比较和==一样效果。充当修饰符:
puts "a比b大" if a > b,这个特性不过是为了写出更符合人类逻辑的语句。检查对象的一致性需要使用
.equal?方法来进行检查和判断。而对于对象值的相等性用==和.eql?就可以了。(注意基本数据类
型的陷阱!)
第六章:循环
- Ruby中实现循环的几(两)种方式:
- 循环语句
- 方法循环:
times\while\each\for\until\loop-
times方法:循环次数.times do |i| puts "#{i}" end -
for方法:for i in 1..5 end # 或者 for item in [1, 2, 3, 4] end -
each方法:[1, 2, 3].each { |item| } -
loop方法:loop do print "Hello for ∞" end -
while和until省略(和Python中的一猫猫一样)
-
- 循环控制:
break,next,redo。三者含义分别是:跳出循环,跳过本次循环(等同于C中的continue), 重新来一次这个循环。 - 题外话
do ~ end写法和{~}的区别:本质上效果一样,不过跨行写程序用前者,否则用后者。
第七章:方法
方法类别:实例方法,类方法,函数式方法
-
方法的标记法:
- 类名#方法名标记类的实例方法:
Array#each - 类名.方法名/类名::方法名标记类方法:
File.open(filename)
- 类名#方法名标记类的实例方法:
方法定义:
def 方法名(参数列表[=默认值]) ... end默认值可选是否添加。方法的返回:可省略
return语句,省略后使用式子最后一个语句进行返回。带块的方法:
yield关键字的使用。具体见下第十一章。接收可变个数参数:
def foo(a, b, *c),这样一来不可逐个指定的参数会以数组形式传给c。-
关键字参数:
def foo(a, b: 1, **args),同样的,多余的参数会以散列的结构存在args参数列表中。反过来亦可以使用散列进行方法、
参数指定,例如:def foo(a: 1, b: 2, **args) end args = {a:100, b:200, c:300} foo(args) 在Ruby社区中有一个特殊的约定:使用两个空白进行缩进
第八章:类
类是面向对象的基础,其重要性不言而喻。类名必须大写!
-
创建类:
def 类名 类的定义 end 类的初始化:使用签名为
initialize的方法。在使用类名.new(args)方式获取对象时,new中的参数会原封不动传给initialize-
存取器:在大部分面向对象的语言中称为
getter和setter方法,在Ruby中由于从对象外部不便直接访问实例变量,所以需要定义相关的
访问方法:class Hello def initialize(name="Bob") @name = name end def name @name end def name=(value) @name = value end end其实关于存取器不用这么麻烦,使用更为便捷的定义方法即可完成实现,下面这个写法和上面实现的功能一样。
class Hello # attr_reader :name # 只定义name实例变量的 name 方法 # attr_writer :name # 只定义name实例变量的 name= 方法 attr_accessor :name # 上面两个合起来 def initialize(name="Bob") @name = name end end 特殊变量
self,一个指向调用者本身的特殊指针,self本身和局部变量形式相同。-
类方法:在其他语言中像Java、C++中称为静态方法(static methods),提供的是一种和类的实例无关而和类本身有关的方法集合。在Ruby中
使用以下方法定义:# 第一种class << 类名 ~ end,这种比较特殊,称为单例类定义 class << Hello def hello(name) puts "#{name}" end end # 第二种def 类名.方法名 ~ end def Hello.hello(name) puts "#{name}" end # 第三种 class Hello def self.hello(name) puts "#{name}" end end上面几种定义之后的方法都可以使用
Hello.hello("Bob")来进行访问调用,具体使用哪一种好,还是仁者见仁智者见智,没有哪一种就一定好
哪一种就一定差的说法。 -
常量:
class HelloWorld version = 1.0 end p HelloCount::version 类变量:在其它语言中称为静态变量,和对象无关,和类本身有关的变量。定义时候使用
@@name定义,访问时使用.访问。-
方法的访问控制:在Ruby中有三种访问级别,分别是
public,protected和private三个。声明方法为作用域法和符号声明法两种。例如:def Point attr_accessor :x, :y protected :x=, :y= # 符号声明,表示x=和y=两个方法均被设置为protected访问级别。 # public # 不指定参数的时候,默认把下面出现的所有方法都设置为public级别。 def initialize(x, y) @x, @y = x, y end end在Ruby中的方法默认使用
public访问级别,但是initialize方法默认使用private访问级别。 扩展类:两种方法,使用继承或者在原有类上添加方法。继承使用
<符号实现,例如:class MyPoint < Point。不过,Ruby只支持单继承。alias和undef:使用alias 别名 原名设置方法别名,也可以直接使用符号来实现alias :别名 :原名来实现。undef用来删除
已经存在的方法,同样有直接使用方法名和符号两种方式实现。-
单例类:使用单例类定义可以给对象添加方法。例如:
str1 = "Bob" class << str1 def hello "Hello, #{self}" end end p str1.hello # 这个时候对于String类的对象str1有了自己独有的hello方法 -
模块:模块帮Ruby实现了多继承,模块不能拥有实例,模块不能被继承。用法如下:
module MyModel1 # 公用的方法 end class MyClass include MyModel1 # 那么MyModel1中的方法可以在以下作用域下使用。 include MyModel2 # 如果MyModel2中有和MyModel1中一样的方法,那么会使用MyModel2中的方法。 end除此之外,模块还可以提供命名空间,例如:
Math::PI或者Math.sqrt方法,这种实现方式需要使用到module_function方法,例如:
module_function :hello extend方法:使用该方法可以批量定义单例方法,obj.extend(模块名),那么模块中的所有方法都可以被定义成单例方法。此外,在类中
使用include包含进来的方法定义为实例方法。在Ruby中的面向对象和Python一样有个特殊约定:鸭子类型(长得像鸭子,走路像鸭子,那就是鸭子)。
第九章:运算符
- 赋值运算符,逻辑运算符和其他程序一样,不赘述。
- 特殊的
&运算符:
不过上面的用法只有在Ruby2.3.0之后才可以使用!类似的方法还有:item = array && array.first # 如果array有效,那么取出array的第一个元素赋给item item = array&.first # 安全运算符或nil检查方法调用。实现的效果和上面的一样。var = var || 1,如果var为空,那么给一个默认值1。 - 定义运算符:除去不能自定义的几个其他都可以,不能定义的有:
:: && || .. ... ?: not = and or。
高度的自由和灵活会带来不可预估的问题——沃兹基索德
第十章:错误处理与异常
- 三个语法:
begin ~ rescue[=>引用异常对象的类和变量] ~ end还有begin ~ rescue[=>引用异常对象的类和变量] ~ ensure ~ end
还有raise [信息][, 异常类]三个,哈哈哈,没了。 - 发生异常后Ruby自动赋值的两个系统变量:
$!和$@前者表示最后发生的异常对象,后者表示异常发生的位置。
第十一章:块
块的存在让Ruby有了很强大的功能,包括算法替换,循环遍历,隐藏常规处理等。
- 语法: 使用
yield关键字来实现。def myloop while true yield "Bob" # yield部分将会替换成块中的程序段,当然,传给yield的参数将会原封不动传给块程序段。 end end myloop do |name| puts "Hello, world,#{name}" end # 上面的程序将会不停输出Hello, World, Bob - 块传递参数:首先可以使用
block_given?来判断是否给出了块程序。 - 控制块的执行:使用
break方法或者next方法以及redo方法,它们可以指定参数,如果不指定会默认返回nil。两者区别:
break会立刻返回调用块处,忽略掉块中的计算结果,返回指定参数或者nil。而next则会中断当前的处理,执行下面的处理,会返
回yield处。redo方法会返回块的开头并重新执行,以相同的块变量进行重复处理。 - 当然,还有将块封装成对象的操作,没看懂哈哈哈哈哈哈。
- 关于局部变量和块变量的作用域:块内部可以使用局部变量,块内部的变量不会影响到外部,即使同名也不行。例如:
x = 1 y = 1 array = [1, 2, 3] array.each do |x| y = x end p [x, y] # [1, 3]
第一、二部分总结
最好的资料呢,来自第一手资料,所以最好的参考文件也是Ruby的官方帮助文件。帮助文件地址:https://www.ruby-lang.org/zh_cn/documentation/
几个看帮助文档的技巧:
- 查阅类和方法时,从Ruby的核心库和标准库开始查找。
- 使用“搜索”功能查找方法。
- 向上追溯查找父类方法。
- 对于API文档,没必要楞记,记住一些元信息,仅在需要的时候阅读需要的部分即可(因为很可能刚背下来的东西一觉起来就解放前了)。
第三部分:Ruby的类
哈哈哈,不学了,等待有需要的时候再回来学习Ruby。再见了,我的红宝石~