Ruby 初体验
print("Hello, \nRuby!")
程序会对双引号里 \
后的字符进行转义,而单引号中的则不会。
puts "Hello, ", "Ruby!"
当参数为两个字符串的时候,各字符串末尾都会加上换行符。
- 使用 p 方法,打印出的数值结果和字符串结果会以不同的形式输出。另外其中的转移符不会转义。
- Ruby 2 开始默认编码使用 UTF-8 编码方式,如果输出中文有乱码的话,可以用 -E 指定输出结果的编码方式。
ruby -E UTF-8 hello.rb
irb -E UTF-8
- irb 命令后的选项 –simple-prompt 会简化 irb 的输出结果。
- 利用 Math 模块进行的数学运算的返回结果是科学计数法 9.26535896604902e-05
--begin
和 =end
中间的部分也是注释。
while
语句可以省略后面的 do
- 正则表达式可以简单的实现:
- 将字符串和模式 pattern 相匹配
- 使用模式分割字符串
- 利用运算符
=~
来匹配模式和字符串。若匹配成功则返回匹配部分的位置,否则返回 nil。
- 使用 ARGV 这个数组来获取从命令行传递过来的数据。从这里得到的数据都是字符串。
- 一下子读取全部数据很消耗内容,改成
File.each_line
就很好了。
Regexp.new(str)
表示把字符串转换成正则表达式对象。
pattern = Regexp.new(ARGV[0])
filenmae = ARGV[1]
file = File.open(filename)
file.each_line do |line|
if pattern =~ line
puts line
end
end
file.close
- 引用 pp 库之后的
pp
方法可以打印出更好的对象。
- 库与脚本放在同一文件夹时,需要用
./
来表示文件存放在当前目录。
Ruby 的基础
并行赋值
a = 1; b = 2; c = 3
a, b, c = 1, 2, 3
- 左右两边数量不相等,也不报错。左边数量较多时,会自动将 nil 赋值给未分配值的变量。
a, b, c, d = 1, 2
p [a, b, c] #=> [1, 2, nil]
- 变量部分较少时,会自动忽略该值,不会分配多余的值。
a, b, c = 1, 2, 3, 4
p [a, b, c] #=> [1, 2, 3]
- 变量前加上 * 表示会将未分配的值封装为数组赋值给该变量。
a, b, *c = 1, 2, 3, 4, 5
p [a, b, c] #=> [1, 2, [3, 4, 5]]
a, *b, c = 1, 2, 3, 4, 5
p [a, b, c] #=> [1, [2, 3, 4], 5]
- 用数组赋值,左边有多个变量时,会自动获取数组的元素进行多重赋值。
ary = [1, 2]
a, b = ary
p a #=> 1
p b #=> 2
a, = ary
p a #=> 1
ary = [1, [2, 3], 4]
a, b, c = ary
p a #=> 1
p b #=> [2, 3]
p c #=> 4
a, (b1, b2), c = ary
p a #=> 1
p b1 #=> 2
p b2 #=> 3
p c #=> 4
条件与真假值
- 不返回 true 或 false 的方法只要能返回 nil,也可以作为条件判断的表达式来使用。
- 为了便于程序理解,返回真假值的方法都要以 ? 结尾。
=== 与 case 语句
case
中的 when
实际是使用 ===
运算符来判断
- 在判断字符串相等的时候
===
和 ==
意义一样
===
还可以与 =~
一样用来判断正则表达式是否匹配
- 判断右边的对象是否属于左边的类
对象的一致性
equal?
方法判断两个对象是否是同一个对象(ID是否相同)
循环
循环时的注意事项
- 循环的主体是什么
- 停止循环的条件是什么
循环控制
命令 |
用途 |
break |
终止程序,跳出循环 |
next |
跳到下一次循环 |
redo |
在相同条件下不断重复刚才的处理。容易陷入死循环,慎用。 |
总结
命令 |
用途 |
times |
确定循环次数时使用 |
for |
从对象取出元素时使用(建议用 each) |
while |
希望自由指定循环条件时时候 |
until |
使用 while 语句使循环条件变得难懂时使用 |
each |
从对象取出元素时使用 |
loop |
不限制循环次数时使用 |
方法
- 调用类方法时可以使用
::
例如 Array.new
等同于 Array::new
- 方法的目的是程序处理,所以允许没有返回值的方法,更准确的说允许返回值是 nil。
- 调用方法时通过块传递进来的处理会在 yield 定义的地方执行
类
一些基础知识
- 想知道对象属于某个类,可以使用
class
方法,判断某个对象属于某个类,可以使用 instance_of?
方法。
- 根据类的继承关系反向追查对象是否属于某个类时,可用
is_a?
方法。
- 我们把通过扩展已定义的类来创建新类成为继承。
- 在不影响原有功能的前提下追加新功能。
- 重定义原有功能,使名称相同的方法产生不同的效果。
- 在已有功能的基础上追加处理,扩展已有功能。
- BasicObject 类是 Ruby 中所有类的父类,定义了 Ruby 对象的最基本功能。
- 定义类时没有指定父类的话,默认该类的为 Object 的子类。
- 使用
new
方法生成新的对象时,会自动调用 initialize
方法。
- 类调用
instance_methods
会以符号形式返回类的实例方法列表。
类的实例及其方法
- 在同一个实例中,程序可以超越方法定义,任意引用,修改实例变量的值。引用未初始化的实例变量时返回值为 nil。
- 从外部对象不能直接访问实例变量,或对实例变量赋值,需要通过方法来访问对象内部。
- 在实例方法中,可以用 self 这个特殊的变量来引用方法的接收者。
- 省略接收者,默认会把 self 作为该方法的接收者。
- 即使对 self 赋值也不生效。
类方法
there are some ways about how to define class method.
class << HelloWorld
def hello(name)
puts "#{name} said hello."
end
end
class HelloWorld
class << self
def hello(name)
puts "#{name} said hello."
end
end
end
class HelloWorld
def self.hello(name)
puts "#{name} said hello."
end
end
- public 以实例方法的形式向外部公开该方法。
- private 在指定接收者的情况下无法调用该方法,也表示只能使用缺省接收者的方式调用该方法,因此无法从实例外部访问。
- protected 在同一个类及其子类中时可将该方法作为实例方法调用。
其它
alias 别名 原名
或者 alias :别名 :原名
- 重定义已存在的方法时,为了能用别名调用原来的方法,我们会用到 alias 方法
undef 方法名
或者 undef :方法名
extend
方法可以使单例类包含模块,并把模块的功能扩展到对象中。
include
帮助我们突破继承的限制,通过模块扩展类的功能。extend
帮助我们跨过类,直接通过模块扩展对象的功能。
module Edition
def edition(n)
"#{self} 第#{n}版"
end
end
str = "Ruby 教材"
str.extend(Edition)
puts str.edition(4)
module ClassMethods
def cmethod
end
end
module InstanceMethods
def imethod
end
end
class MyClass
extend ClassMethods
include InstanceMethods
end
MyClass.cmethod
MyClass.new.imethod
模块
- 类表现的是事物的数据和行为,模块只表现行为部分。
- 命名空间可以对方法,常量,类等名称进行区分及管理。
module_function :hello
定义模块函数。
- 使用 模块名.方法名 的形式来调用在模块中定义的方法,这样的方法成为模块函数。
- include 方法可以把模块内的方法,常量合并进入当前的命名空间。
- 如果没定义与模块内的方法,常量同样的名称,就可以省略模块名,直接调用。
- 不建议在定义为模块函数的方法内部使用 self
- 想知道类是否包含某个模块,可以使用
include?
方法,ancestors
取得继承关系的列表。
面向对象编程
- 对象之间通过方法交换信息,不关心彼此内部是如何处理的。
- 封装指对象管理的数据不能直接从外部进行操作,数据的更新,查询等操作必须通过调用对象的方法来完成。
- 多态指各个对象都有自己独有的消息解释权。一个方法名属于多个对象,不同对象的处理结果不一样。
- 鸭子类型是指对象的特征不是由其类及其类的继承关系来决定的,而是由对象本身具有什么样的方法决定的。