单引号与双引号:
单引号不会自动解析特殊符号,会将单引号之间的所有内容打印出来,如:
P ‘hello,\nruby\n!\n’就会打印出:hello,\nruby\n!\n。
而双引号P “hello,\nruby\n!\n”会打印出:
Hello,
Ruby
!
puts "1+1=#{1+1}"的效果也一样。
因此,需要原封不动的打印时用单引号,需要解析特殊符号时用双引号。
puts、print、p、pp:
Puts会在每个双引号结束时都加一个换行,如puts (“a”,”b”)就会显示:
a
b
print的结尾不会自动换行,如print “a”,”b”会显示ab。需自己加\n来换行。用在程序要显示出执行结果或消息时。
P会将双引号一起显示出来,并且会自动换行。如p “l”会显示”l”。用在想要观察执行中的程序运行情况时,是为写程序的人而设计的方法。
Pp方法会更直观的显示结果。pp会把哈希分多行显示,而p会在一行显示。
Ruby的库函数的使用:
如要使用Math模块里的函数,如sin, sqrt等,就要在最开始include Math,然后直接给对象用这些函数,如puts sqrt(100)等。
也可以不Include,而使用puts Math.sqrt(100)。
两个文件互相调用对方的方法:
如aa.rb调用bb.rb里定义的方法fun1(),必须在aa.rb的最前面include “bb”,然后直接使用fun1()即可。
总结:
Include方法既可以引入标准库中的模块,include “模块名”;也可以引入其它rb文件,include “文件名”。
Ruby与C的不同之处:(蓝色部分为可省)
(1) C中的if语句没有end,而ruby有,ruby中的形式为:
if 条件 then
要执行的动作
elsif 条件 then
要执行的动作
else
要执行的动作
end
为了突出动作和简洁性,还可以写成:
要执行的动作 if 条件 【此时不用写end】
(2) C中的while语句也没有end,而ruby中的while语句有:
While 条件 do
要执行的动作
End
(3) 循环:ruby的for语句和C语言的for语句格式不同:
for 变量 in 起始值..终止值
动作
end
或
for 变量 in 对象
动作
end
同时有times方法,用于循环次数确定时:
100.times{
要执行的动作
}
(4) ruby中有unless方法:【与If语句作用正好相反,Unless后的条件不成立时才执行后面的语句。】
unless 条件 then
语句
else
语句
end
(5) case语句的格式:【case语句经常用在数组或者哈希的each方法内部】
case 要比较的对象
when 值1 then
语句1
when 值2 then
语句2
else
语句3
end
Ruby迭代器:times, each等。
Ruby过滤器:
对全体数据进行某些特定的处理并输出的程序称为过滤器。比如pp方法(pretty print)就是对全体数据按一定规则排列后再输出。
Ruby容器:(container)
像数组、哈希这种用来存放对象的对象,称为容器。
Ruby取数组的index和哈希的key:
b = [‘a’,’b’]
a = {‘name’ => ‘rose’,…….}
只能用b[0]、a[‘name’]来得到该index/键对应的值,而不能用b[‘a’]和a[‘rose’]。
(哈希中的键相当于数组中默认的index。)
要想取数组的index和哈希的key,必须用数组对象的index方法和哈希对象的key方法:b.index('a')和a.key('rose')。(返回0和”a”)
较好的例子:
一:打印出下面的字符串中所有含有abc(不区分大小写)的字符串。
str = [ 'a','b','addb','abcd','Abced']
str.each{ |item|
if /abc/i =~ item #用正则表达式来匹配
puts item
end
}
结果:abcd Abced
Ruby全局变量(以$开头):
在整个.rb文件中都是唯一的,而且在一个.rb文件中引入了另一个.rb文件,同时这两个文件中都有一个相同名称的全局变量,就会把这两个全局变量看成一个全局变量,它们之间是会互相影响的。全局变量会使程序跟踪困难。因此,不提倡使用全局变量。
举例:
test1.rb:
$x = 1
x = 1
test2.rb
$x = 0
x = 0
p $x # 0
p x # 0
require ‘test1’
p $x # 1
p x # 0
Ruby命名规则:
采用长命名方式,不要用简称;
单词之间用下划线隔开;
如果某个方法返回的是真假,习惯上在方法名后加个?;
Ruby对象:
对象有两个属性:对象的ID与对象的值。
(1)每个对象都有唯一的一个ID来标识,用equal?来判断两个对象是不是同一个对象,即对象ID是否相同。
(2)用==或者eql?来判断对象的值是否相同,区别:
==比较时自动会进行必要的变换,如 p 1.0 == 1,输出true;
eql?比较时会很严格,p 1.0.eql?1,输出false。
Ruby的条件判断:
除了if语句、case语句之外,还有一种unless语句。
Ruby中的 === 符号:
若左边是数值或字符串,则相当于 ==;
在正则表达式下,相当于 =~;
在类的场合下,则是判断 === 右边的对象是否是类的实例。
Ruby中的循环:——熟练使用times/each/while三种!
(1)times方法:——重复处理固定次数,i必须从0开始
10.times {
puts “hello”
}
或
10.times do
puts “hello”
end
还可以写成:【i从0开始】
10.times { |i|
print "this is ",i,"\n"
}
(2)for语句:——可自由的定义起始值和终止值
第一种:
for 变量 in 起始值..终止值
动作
end
举例:
Sum = 0
for i in 10..20
puts i
sum = sum+i
end
puts sum
第二种:
for 变量 in 对象
动作
end
举例:
names = [‘a’,’b’,’c’]
for i in names
puts i
end
(3)while语句:
while 条件 do
语句
end
(4)until语句:——条件不成立时执行,与while相反。
until 条件 do
语句
end
(5)each方法:——与for的第二种用法类似,但一般都用each方法。
对象.each{ |i|
语句
}
或
对象.each do |i|
语句
end
(5)loop方法:
loop{ 语句 }
将一直循环下去,必须配合break指令。
Ruby中的循环控制语句:
(1) break——停止动作,马上跳出整个循环
(2) next——直接跳到下一次循环
(3) redo——以相同的条件重新进行这一次循环
Ruby中的类方法:
接收者不是对象而是类。会产生一个该类的对象。例如:
a = Array.new
file = File.open(“test1”)
time = Time.new
改变实例变量——巧妙的方法名称
Class HelloWorld
………..
Def name #读实例变量,getter方法
Return @name
End
Def name= (value) #写实例变量,setter方法
@name = value
End
End
Bob.name 返回Initialize中默认的初始值
Bob.name= “Tom” 返回Tom。
看上去像是幅值语句,其实是在调用name=()这个方法。
attr_reader、attr_writer、attr_accessor方法
如果实例变量很多时,每个变量都要定义上面的读和写变量的方法,很麻烦,ruby提供了三个方法来自动产生等效的功能。
使用方法:
attr_reader :name #读实例变量,getter方法
attr_writer :name #写实例变量,setter方法
attr_accessor :name #此一句就相当于上述name和name=读和写两个方法。
类方法的定义,除了使用类名.方法名之外,还有两种形式,self.方法名和class << 类名。一般都用第一种,但应该认识其他两种。
常数——大写字母开头,可直接访问,值不能改。
在类内定义的常数,在类外访问时,用类名::常数名的形式访问。
Class HelloWorld
Version = “1.0”
…..
End
P HelloWorld::Version
类变量——@@开头,小写字母。必须通过定义类方法来访问和修改值。
self在不同地方时的意义
(1) 在实例方法中,self代表实际使用该方法的那个对象。
(2) 在类中且在实例方法外,self代表这个类。
扩充类
即在已经定义的类中新增方法,可以去类的定义部分增加代码,也可以在任意的地方新增代码。如果要对ruby的基础类新增方法,则只能在其他地方新增代码了。比如在String类中新增用来计算字符串中单词数量的方法count_word:
class String
def count_word
ary = self.split(‘ ’)
return ary.size
end
end
str = “I am a girl”
p str.count_word # 输出4
定义或重载运算符——与定义方法类似,只不过方法名变为了运算符符号。
Def [ ] (i)
….
End
继承的本质
父类与子类不一定要是“父”与“子”的关系,一般将多个类的共同部分定义在父类中,在子类中定义各自不一样的地方。有时候父类一般是不会直接产生对象的,父类的存在可能只是提供多个子类的共同部分,便于管理和定义罢了。
例如ruby中所有类都是Object类的子类,其中定义了一些最最基本的熟悉和方法,但一般不会用Object类来产生对象。
Public private protected方法:
默认为public;
public可以在外部通过实例来调用。
Initialize恒为private;
Private的只能在内部使用,不能在类的外部用对象.方法的形式调用。
Protected的方法也只能在内部使用,不能在类的外部直接调用,但是可以在同一个类中的其他方法中调用该protected的方法,这里的其他方法可以是public的。
Duck Typing
举例:
对于数组:a = [“BO”,”FO”,”CO”] 和哈希:s = {0=>”BO”,1=>”FO”,2=>”CO”},都可以用a[1]或者s[1]来取值,且都有downcase的方法。那么此时对于这两种数据类型,就可以用相同的方法来处理。如:
def fetch_and_downcase(x, index)
if xx = x[index]
return xx.downcase
end
end
P fetch_and_downcase(a,1) # fo
P fetch_and_downcase(s,1) # fo
这就是ruby的Duck Typing的特点。即对于不同的东西,只要能进行相同的操作,就可以统一处理,避免了对不同类型的对象都要写一遍相同的方法的麻烦。
模块的用法
1. 提供命名空间
比如有方法名相同、功能不同的两个方法,就可以分别写在两个模块中,再用模块名.方法名的形式调用方法。或者include该模块然后直接使用方法。如使用Math模块中的sqrt方法,可以用Math.sqrt(2),也可以include Math,然后直接用sqrt(2)。
2. 以Mix-in方式在类内include模块
如果两个类有几个相同的方法,就可以把这几个方法抽象出来写在一个模块里,再在每个类中include这个模块。这种方式一般用在:
两个类具有相似的功能,但并不想归类于相同的类时;
这两个类已经是从某些类继承下来的,ruby不允许一个类有多个父类,因此可以用这种方式。
3. 将多个相关的类放在一起统一管理
数组的建立
1 普通方法,即str = [‘a’,’b’]
2 Array.new的方法:
A = Array.new # [ ]
A = Array.new(5) # [nil, nil, nil, nil, nil]
A = Array.new(5,0) #[0,0,0,0,0]
这种方法适合于产生多个元素内容相同的数组。
3 %w的方法:
A = %w(a b c d e f g) # [“a”, “b”, ….]
适合于产生字符数组
4 使用to_a将其它类型(如哈希)转换为数组
5 使用split将字符串切割成数组
数组的操作
(1)可以通过索引来:
获取或改写一个:a[2]或a.at(n)或a.slice(n)
获取或改写从n到m多个:a[n..m]或a.slice(n..m),及a[n…m]
获取或改写从n开始的多个:a[n,len]或a.slice(n,len)
在n后面插入若干个:a[n,0]=[‘x’,’y’]、
跳着取值或改写多个:a.values_at(1,3,5)
等操作。
(2)可以将数组看做集合,求交集 & 和并集 | 、差集即相减、相加等操作。
(注意相加与求并集的区别)
(3) 以堆栈和队列的方式操作数组
a = [‘a’,’b’,’c’]
从前方插入和删除:
a.unshift(‘o’)
a.shift
从后方插入和删除:
a.push(‘d’) 或 a << ‘d’
a.pop
若只想取第一个或最后一个,而不希望删除数组中的该元素,用a.first和a.last。
(4)将两个数组连成一个
a = [1,2] b = [3,4]
a.concat(b)或a.concat([3,4]) 则a就变成了[1,2,3,4]
a+b则会返回新的数组,a仍然是原来的[1,2]