|真|假| |–|–| |真|false、nil以外的所有对象| |假|false、nil|
if 条件 then
end
then 可以省略
条件为假时执行
unless 条件 then
end
then 可以省略
case 比较对象
when 值1 then
处理1
when 值2 then
处理2
when 值3 then
处理3
else
处理4
end
then 可以省略
在case语句中,when判断值是否相等时,实际是使用===运算符来判断。左边是数值或字符串时,===与==意义一样,除此之外,===还可以与=~一样用来判断正则表达式是否匹配,或者判断右边的对象是否属于左边的类,等等。对比单纯的判断两边的值是否相等,===能表达更加广义的”相等”。
例如:0 与 0.0 和 1.0 与 1 eql? 返回 false ==返回 true
# 满地油菜花输出7遍
7.times do
puts "满地油菜花"
end
得到当前的循环次数
10.times do |i|
puts i
end
for语句与times方法不一样,循环的开始值和结束值可以任意指定。
sum = 0
for i in 1..5 do
sum = sum + i
end
puts sum
do可以省略
计算变量from到变量to累加的总数
from = 10
to = 20
sum = 0
for i in from..to
sum = sum + i
end
puts sum
names = ["awk", "Perl", "Python", "Ruby"]
for name in names
puts name
end
i = 1
while i < 3
puts i
i += 1
end
until语句的结构与white完全一样,只是条件判断刚好相反,不满足条件时才执行循环处理
each方法将对象集合里的对象逐条取出
names = ["awk", "Perl", "Python", "Ruby"]
names.each do |name|
puts name
end
sum = 0
(1..5).each do |i|
sum = sum + i
end
puts sum
loop方法没有终止条件,只是不断的执行循环
break会终止全体循环程序
next会忽略next后面的部分,跳到下一个循环开始的部分
redo和next非常像,与next不同之处是,redo会再执行一次相同的循环 break和next比较常用,redo在ruby默认提供的程序库里也很难找到踪影
一般的约定
对象.方法名(参数1, 参数2, … ,参数n)
对象被称为接收者(receiver)。在面向对象的世界中,调用方法被称为『向对象发送消息(message)』,调用的结果就是『对象接收(receive)了消息』,也就是说,方法的调用就是把几个参数连同消息一起发送给对象的过程。
each 和 loop 等方法都属于带块的方法
使用do ~ end是,可以省略参数列表括起来的()。使用{~}时,只有在没有参数的时候才可以省略()。
Ruby中有些方法看起来很像运算符。四则运算等的二元运算符、-(负号)等的一元运算符、指定数组、散列的元素下标的[]等,实际都是方法。
实际上可以将obj理解为接收者,将arg1、arg2理解为参数。
Ruby的方法分为3类:
如果有一个对象的实例,那么以这个对象为接收者的方法就是实例方法。
p "10, 20, 30, 40".split(",")
p [1, 2, 3, 4].index(2)
p 1000.to_s
接收者不是对象而是类本身时的方法,是类方法。
Array.new
File.open("some_file")
Time.now
调用类方法时,可以使用::代替.。Ruby语法中 :: 和 . 代表的意思是一样的。
没有接收者的方法是函数式方法。
print "hello!"
sleep(10)
函数式方法的执行结果,不会根据接收者的状态而发生变化。程序运行print方法以及sleep方法的时候,不需要知道接收者是谁。反过来说,不需要接收者的方法就是函数式方法。
Ruby帮助文档里标记类的实例方法用Array#each、Array#inject写法。
定义方法的一般语法:
def 方法名 (参数1, 参数2)
希望执行的代码
end
方法名可以由英文字母、数字、下划线组成,但不能以数字开头。
方法有多个参数时,从参数列表右边开始依次指定默认值。
def func(a, b=1, c=3)
end
可以用return指定方法的返回值
可以省略return语句,方法的最后一个表达式的结果作为方法的返回值
return语句可以马上终止程序
def myloop
while true
yield # 执行块
end
end
num = 1 # 初始化num
myloop do
puts "num is #{num}"
break if num > 100 # num超过100时跳出循环
num * 2
end
yield是定义块的关键字
通过 『*变量名』 的形式来定义参数个数不确定的方法
def foo(*args)
args
end
p foo(1, 2, 3) #=> [1, 2, 3]
def meth(arg, *args)
[arg, args]
end
p meth(1) #=> [1, []]
p meth(1, 2, 3) #=>[1, [2, 3]]
Ruby 2.0加入的新特性
def 方法名(参数1:值, 参数2:值)
代码逻辑
end
可以使用 『**变量名』这种形式来接收未定义的参数
关键字参数可以与普通参数搭配使用
可以使用散列传递参数
想知道某个对象属于哪个类,可以使用class方法
ary = []
str = 'Hello World.'
p ary.class #=> Array
p str.class #=> String
判断某个对象是否属于某个类时,使用instance_of?方法
ary = []
str = 'Hello World'
p ary.instance_of?(Array) #=> true
p str.instance_of?(String) #=> true
p ary.instance_of?(String) #=> false
p str.instance_of?(Array) #=> false
使用class关键字定义类
class 类名
类的定义
end
使用new方法生成新对象时,initialize方法会被调用,new方法的参数会原封不动的传给initialize方法
# initialize方法
def initialize(myname='Ruby')
@name=myname # 初始化实例变量
end
实例方法在实例内可用
class HelloWorld
# 获取name
def name
@name
end
# 修改name
def name=(value)
@name = value
end
Ruby提供了简便的定义方法
self是引用对象本身的保留字,对它赋值,不会对本身的值有任何影响
class << HelloWorld
def hello(name)
puts "#{name} said hello."
end
end
HelloWorld.hello('John') #=> John said hello.
class HelloWorld
class << self
def hello(name)
puts "#{name} said hello."
end
end
end
HelloWorld.hello('John') #=> John said hello.
def HelloWorld.hello(name)
puts "#{name} said hello."
end
HelloWorld.hello('John') #=> John said hello.
class HelloWorld
def self.hello(name)
puts "#{name} said hello."
end
end
HelloWorld.hello('John') #=> John said hello.
class HelloWorld
Version = "1.0"
end
使用类常量
p HelloWorld::Version #=> "1.0"
@@开头的变量称作类变量,类变量是该类所有实例的共享变量
class HelloCount
@@count = 0
def HelloWorld.count
@@count
end
def initialize(myname="Ruby")
@name = myname
end
def hello
@@count += 1
puts "Hello, World. I am #{@name}.\n"
end
end
bob = HelloCount.new("Bob")
alice = HelloCount.new("Alice")
ruby = HelloCount.new
p HelloCount.count #=> 0
bob.hello
alice.hello
ruby.hello
p HelloCount.count #=> 3
限制方法的调用
给String类添加统计单词数实例方法
class String
def count_word
ary = self.split(/\s+/) # 使用空格分割
return ary.size # 返回分割后数组元素总数
end
end
str = "Just Another Ruby Newbie"
p str.count_word #=> 4
定义继承时,在使用class关键字指定类名的同时指定父类名
class 类名 < 父类名
类定义
end
class RingArray < Array
def [](i)
idx = i % size
super(idx)
end
end
wday = RingArray['日', '火', '水', '木', '金', '土']
p wday[6] #=> '土'
p wday[11] #=> '木'
p wday[15] #=> '月'
p wday[-1] #=> '土'
alias 别名 原名 # 直接使用方法名
alias :别名 :原名 # 使用符号名
同一种功能设置多个名称时,我们使用alias
class C1
def hello
"Hello"
end
end
class C2 < C1
alias old_hello hello
def hello
"#{old_hello}, again"
end
end
obj = C2.new
p obj.old_hello
p obj.hello
undef用于删除已有方法的定义。
undef 方法名 # 只用使用方法名
undef :方法名 # 使用符号名
模块是Ruby的特色功能之一。如果说类变现的是事物的实体(数据)和行为(处理),那模块表现的就只是事物的行为部分。模块和类有两点不同:
调用方法
模块名.方法名
Mix-in就是将模块混合到类中
Mix-in可以灵活的解决下面问题:
module MyModule
# 共通的方法
end
class MyClass1
include MyModule
# MyClass1独有方法
end
class MyClass2
include MyModule
# MyClass2独有方法
end
module 模块名
模块定义
end
module HelloModule
Version = "1.0"
def hello(name)
puts "Hello, #{name}"
end
module_function :hello
end
p HelloModule::Version #=> "1.0"
module M
def meth
"meth"
end
end
class C
include M
end
c = C.new
p c.meth
C.include?(M) #=> true
p C.ancestors #=> [C, M, Object, BasicObject]
p C.superclass #=> Object
module Edition
def edition(n)
"#{self} 第#{n}版"
end
end
str = "Ruby基础教程"
str.extend(Edition)
p str.edition(4) #=> "Ruby基础教程第4版"
include可以帮助我们突破继承的限制,通过模块扩展类的功能;而extend则可以帮助我们跨过类,直接通过模块扩展对象的功能。
我们可以把类方法理解为:
面向对象语言的「对象」是指数据及操作数据方法的组合
条件 ? 表达式1 : 表达式2
范围对象range
Range.new(1, 10)
1..10
x..y是从x到y x…y是从x到y的前一个
从高到低排序
| ^ |
= < <=
如果不想按照优先顺序计算,可以使用()起来
不允许修改的运算符
begin
可能发生错误的处理
rescue
发生错误时的处理
end
rescue后指定变量名,可获得异常对象
begin
可能发生错误的处理
rescue => 引用异常对象的变量
发生错误时的处理
end
异常发生时被自动赋值的变量:
异常对象的方法:
块就是在调用方法时,能与参数一起传递的多个处理的集合
[1, 2, 3, 4, 5].each do |i|
puts i ** 2
end
do和end之间的就是块
a.compact a.compact!
从数组a中删除nil元素。 compact方法返回新数组,compact!则直接替换原来的数组
a.delete(x) 从数组a删除x元素
a = [1, 2, 3, 2, 1]
a.delete(2)
p a #=> [1, 3, 1]
a.delete_at(n) 从数组a中删除a[n]元素
a = [1, 2, 3, 4, 5]
a.delete_atl(2)
p a #=> [1, 2, 4, 5]
| a.delete_if{ | item | … } |
| a.reject{ | item | … } |
| a.reject!{ | item | … } |
判断数组a中个元素item,如果块的执行结果为真,则从数组a中删除item。delete_if和reject!方法都是具有破坏性的方法。
a.slice!(n) a.slice!(n..m) a.slice!(n, len) 删除数组a中指定的部分,并返回删除部分的值。slice!是具有破坏性的方法。
a = [1, 2, 3, 4, 5]
p a.slice!(1, 2) #=> [2, 3]
p a #=> [1, 4, 5]
a.uniq a.uniq!
删除数组a中重复的元素,uniq!是具有破坏性的方法
a = [1, 2, 3, 4, 3, 2, 1]
a.uniq!
p a #=> [1, 2, 3, 4]
a.shift 删除数组a开头的元素
a.pop 删除数组a末尾的元素
迭代器是实现循环处理的方法,而数组则是多个对象的集合
list = ["a", "b", "c", "d"]
for i in 0..3
print "第", i+1,"个元素是",list[i],".\n"
end
list = [1, 3, 5, 7, 9]
sum = 0
list.each do |elem|
sum += elem
end
print "合计:",sum,"\n"
指定元素索引值 each_with_index
list = ["a", "b", "c", "d"]
list.each_with_index do |elem, i|
print "第", i+1, "个元素是", elem,".\n"
end
while item = a.pop
## 对item进行处理
end
参考 11.3
a = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
取出元素6
a[1][2]
str1 = "这是字符串"
str2 = '那也是字符串'
使用\转义特殊字符
desc = %Q{Ruby的字符串中也可以使用''和""}
str = %q|Ruby said, 'Hello world!'|
Here Document源于Unix的shell的一种写法,«来创建字符串
参考printrf方法与sprintf方法
irb --simple-prompt
`ls -l /etc/hosts`
length和size方法获得字符串长度,两者的返回结果相同。
p '面向对象编程语言'.length #=> 8
需要获得字节数可以使用bytesize方法
p '面向对象编程语言'.bytesize #=> 24
想知道字符串长度是否为0,使用empty?方法
str = "全新的String类对象"
p str[0] #=> "全"
p str[3] #=> "S"
p str[2, 8] #=> "的String类"
连接字符串的两种方法:
使用==或者!=判断字符串是否相等
s.reverse s.reverse! 反转字符串
s = "晚上好"
p s.reverse #=> "好上晚"
s.strip s.strip!
这是删除字符串s开头和结尾空白字符的方法
{键 => 值}
h1 = {"a"=>"b", "c"=>"d"}
p h1["a"] #=> "b"
{健: 值}
h2 = {a: "b", c: "d"}
p h2 #=> {:a=>"b", :c=>"d"}
h1 = Hash.new
h2 = Hash.new("")
p h1["not_key"] #=> nil
p h2["not_key"] #=> ""
使用[]获取键相对应的元素值
h = Hash.new
h["R"] = "Ruby"
p h["R"] #=> "Ruby"
另外可以使用store方法设定,fetch方法获取值
h = Hash.new
h.stroe("R", "Ruby")
p h.fetch("R") #=> "Ruby"
使用fetch方法时,有一点与[]不一样,如果散列中不存在指定键,程序会发生异常; 如果对fetch方法指定第2个参数,那么该参数值就会作为键不存在时散列的默认值; fetch方法还可以使用块,此时块的结果为散列的默认值
h = Hash.new
p h.fetch("N"){String.new} #=> ""
| 迭代器形式: each_key{ | 键 | ……} |
| 迭代器形式: each_value{ | 值 | ……} |
| 迭代器形式: each{ | 键, 值 | ……} each{ | 数组 | ……} |
h = Hash.new(1)
h["a"] = 10
p h["a"] #=> 10
p h["x"] #=> 1
p h["y"] #=> 1
h = Hash.new do |hash, key|
hash|key| = key.upcase
end
p h["a"] #=> "b"
p h["x"] #=> "x"
p h["y"] #=> "y"
h.key?(key) h.has_key?(key) h.include?(key) h.member?(key)
上面4个方法都是查看指定对象是否为散列的键的方法,用法和效果都一样
h.value?(value) h.has_value?(value) 上面两2个方法用来检查值是否在指定的对象中
可以用length方法或者size方法查看散列的大小
可以empty?方法来查看散列的大小是否为0
通过键删除用delete方法,delete方法可以使用块,如果不存在键,返回块执行结果
h = {"R"=>"Ruby"}
p h.delete("P"){|key| "no #{key}."} #=> "no P."
| h.delete_if{ | key, val | ……} |
| h.reject!{ | key, val | ……} |
h = {"R"=>"Ruby", "p"=>"Perl"}
p h.delete_if{|key, value| key == "P"} #=> {"R"=>"Ruby"}
reject!方法和delete_if方法用法相同,但当不符合条件时,两者返回值各异。delete_if返回原来的散列,reject!返回nil
使用clear方法清空使用过的散列
h = {"a"=>"b", "c"=>"d"}
h.clear
p h.size #=> 0
一般情况我们把正则表达式对象(Regexp类对象)称为『正则表达式对象』,或直接称为『正则表达式』
在程序中,通过用//将正则表达式模式的字符串括起来,就可以非常简单的创建出正则表达式
另外可以使用类方法Regexp.new(str)来创建对象
re = Regexp.new("Ruby")
使用%r创建正则表达式
%r(模式)
%r<模式>
%r|模式|
%r!模式!
正则表达式 =~ 字符串
无法匹配时返回nil,匹配成功返回该字符串起始字符的位置
if 正则表达式 =~ 字符串
匹配时处理
else
不匹配时处理
end
可以使用!~颠倒「真」与「假」
有时候我们想匹配『ABC』中的1个字符,可以使用[]
[AB] # 匹配A或B
[ABC] # 匹配A或B或C
[CBA] # 同上,与[]中的顺序无关
[012ABC] # 0、1、A、B、C中的一个字符
使用.匹配任意1个字符
正则表达式还有选项,使用选项可以改变正则表达式的一些默认效果。 设定正则表达式的选项时,只需在/…/后面指定即可,如:/…/im
所谓捕获,就是从正则表达式的就匹配部分中提取其中的某部分。通过”$数字”这种形式的变量,就可以获取匹配了正则表达式中用()扩住的部分字符串。
除了”$数字”这种形式,保存匹配结果的变量还有:
/C./ =~ 'ABCDEF'
p $\`` #=> "AB"
p $& #=> "CD"
p $' #=> "EF"
sub方法与gsub方法的作用是用指定的字符串置换字符串中的某部分字符
sub方法只置换首次匹配的部分,而gsub方法则会置换所有匹配的部分
str = "abc def g hi"
p str.sub(/\s+/, ' ') #=> "abc def g hi"
p str.gsub(/\s+/, ' ') #=> "abc def g hi"
sub方法和gsub方法还可以使用块,这时程序将字符串中匹配的部分传递给块,并在块中使用该字符串进行处理。
sacn方法像gsub方法那样捕获匹配部分的字符串,但不能做置换操作