2008年12月17日 星期三
ruby 主要的系统变量以及它们的含义
转载: RUBY文档中心 http://www.moer.net/ruby/doc/ReadQuestion.asp?QuestionID=114
$! 最近一次的错误信息
$@ 错误产生的位置
$_ gets最近读的字符串
$. 解释器最近读的行数(line number)
$& 最近一次与正则表达式匹配的字符串
$~ 作为子表达式组的最近一次匹配
$n 最近匹配的第n个子表达式(和$~[n]一样)
$= 是否区别大小写的标志
$/ 输入记录分隔符
$\ 输出记录分隔符
$0 Ruby脚本的文件名
$* 命令行参数
$$ 解释器进程ID
$? 最近一次执行的子进程退出状态
Ruby 學習
Ruby 學習
$ 全局变量
@ 实例变量
@@ 类变量, ,类变量在使用前必须要初始化
类名、模块名和常量应该用大写字母开头
字符串是在’’ (单引号), “ “(双引号)之间的代码
数组的下标从0开始。Ruby的数组和其它语言不同,数组的每个元素可以是不同的类型:[ 2.4, 99,“thank you”,[ a, b ,c ] ,78 ]。
区间:
1..5 表示1,2,3,4,5
1...5表示1,2,3,4 。
// ---------------------------------------------------
Ruby里,nil 和 false 为假,其它都为真
// --------------------------------------------------
a,b,c = x, (x+1), (x+2) #a=0 ,b=1,c=2
// ----------------------------------------------------------------
条件判断语句
一. 单行 if(如果) 语句
1) if 条件 then 语句1; 语句2 ; 语句… end
2) ( 语句1; 语句2 ; 语句… ) if 条件
二. 多行 if 语句
if 条件
语句1; 语句2 ; 语句…
elsif 条件
语句1; 语句2 ; 语句…
else
语句1; 语句2 ; 语句…
end
// -----------------------------------------------------------------
循环语句
一. while(当…) 循环
while 条件
语句1; 语句2 ; 语句…
end
二. 单行 while 循环
( 语句1; 语句2 ; 语句… ) while 条件
// ---------------------------------------------------------------
在循环体内,如果遇到:
break ,跳出当层循环;
next ,忽略本次循环的剩余部分,开始下一次的循环;
redo ,重新开始循环,还是从这一次开始;
retry ,重头开始这个循环体。
// ---------------------------------------------------
3.times { print "Hi!" } #Hi!Hi!Hi!
1.upto(9) {|i| print i if i<7> #123456
9.downto(1){|i| print i if i<7> #654321
(1..9).each {|i| print i if i<7}> #123456
0.step(11,3) {|i| print i } #0369
//--------------------------------------------------------
CLASS
class Person
def initialize( name, age=18 )
@name = name
@age = age
@motherland = "
end #初始化方法结束
def talk
puts "my name is "+@name+", age is "+@age.to_s
if @motherland == "
puts "I am a Chinese."
else
puts "I am a foreigner."
end
end # talk方法结束
attr_writer :motherland
end # Person类结束
p1=Person.new("kaichuan",20)
p1.talk
@age.to_s的含义是:将数@age转换为字符串。
attr_writer :motherland 相当于
def motherland=(value)
return @motherland =value
end
attr_ reader :motherland 相当于
def motherland
return @motherland
end
attr_accessor :motherland 相当于attr_reader:motherland; attr_writer :motherland
// ----------------------------------------------
继承
class Student < Person
def talk
puts "I am a student. my name is "+@name+", age is "+@age.to_s
end # talk方法结束
end # Student类结束
// ------------------------------------------------------------------------------------------------------------
Ruby 是动态语言,你可以改变 Ruby 程序的结构,功能,在Ruby程序运行中。方法、属性可以被加入或去除,
新的类或对象可以被建立,新的模块可以出现
# E5.4-1.rb
class Person
def talk
puts "Today is Saturday. "
end
end
p1=Person.new
p1.talk # Today is Saturday.
class Person
def talk
puts "Today is #@date. "
end
attr_accessor :date
end
p1.date="Sunday"
p1.talk # Today is Sunday.
class Person
undef :talk
end
#p1.talk talk方法已经不存在
// --------------------------------------------------------------------
Ruby支持缺省参数
def sum( a, b=5 )
a+b
end
puts sum(3,6) #9
puts sum(3) #8
// ----------------------------------------------------------------------
Ruby还支持可变参数
# E6.1-2.rb
def sum( *num )
numSum = 0
num.each { |i| numSum+=i }
return numSum
end
puts sum() #0
puts sum(3,6) #9
puts sum(1,2,3,4,5,6,7,8,9) #45
// --------------------------------------------------------------------------
增强父类方法
Super
#E6.2-1.rb
class Person
def talk(name)
print "my name is #{name}."
end
end
class Student < Person
def talk(name)
super
print "and I'm a student.\n"
end
end
aPerson=Person.new
aPerson.talk("kaichuan") #my name is kaichuan.
print "\n\n"
aStudent=Student.new
aStudent.talk("kaichuan") #my name is kaichuan.and I'm a student.
// -------------------------------------------------------------------------------------
在Ruby里,可以给具体的实例对象添加实例方法,这个方法只属于这个实例对象,我们把这样的方法称之为单例方法。
#E6.4-1.rb
class Person
def talk
puts "Hi! "
end
end
p1=Person.new
p2=Person.new
def p2.talk #定义单例方法p2.talk
puts "Here is p2. "
end
def p2.laugh #定义单例方法p2. laugh
puts "ha,ha,ha... "
end
p1.talk # Hello!
p2.talk # Here is p2.
p2.laugh # ha,ha,ha...
// -----------------------------------------------------------------------------------------
访问控制
public 可以被任何实例对象调用,不存在访问控制;
protected 可以被定义它的类和其子类访问,可以在类中或子类中指定给实例对象;
private 可以被定义它的类和其子类访问,不能被实例对象调用。
#E6.5-1.rb
class Person
def talk
puts " public :talk, 将调用speak"
speak
end
def speak
puts "protected :speak,将调用laugh"
laugh
end
def laugh
puts " private:laugh"
end
protected :speak
private :laugh
end
p1=Person.new
p1.talk
#p1.speak 实例对象不能访问protected方法
#p1.laugh 实例对象不能访问private方法
// -------------------------------------------------------------------------------------------------------------
模块
在程序中,相关的、不相关的代码的组合,叫作模块
把功能相关的程序代码放在一个模块里,体现了模块的第一个作用:可以被其它程序代码重复使用。
#E7.1-1.rb
puts Math.sqrt(2) # 1.4142135623731
puts Math::PI # 3.14159265358979
Ruby标准包里的 Math 模块提供了许多方法,比如:求平方根 sqrt ,
使用的时候要这么写:模块名.方法名(参数)。
定义模块用module...end 。模块与类非常相似,但是:
A) 模块不可以有实例对象;
B) 模块不可以有子类。
// ---------------------------------------------------------------------------------------------------
命名空间
模块的第二个作用:提供了一个命名空间(namespace),防止命名冲突。
module Me
def sqrt(num, rx=1, e=1e-10)
num*=1.0
(num - rx*rx).abs
end
end
include Math
puts sqrt(293) # 17.1172427686237
#puts sqrt(293, 5, 0.01)
include Me
puts sqrt(293) # 17.1172427686237
puts sqrt(293, 5, 0.01) # 17.1172429172153
只要include模块名,就能使用不同模块的sqrt方法
#E7.3-1.rb
module Me
def sqrt(num, rx=1, e=1e-10)
num*=1.0
(num - rx*rx).abs
end
end
class Person
def talk
puts "I'm talking."
end
end
class Student < Person
include Me
end
aStudent=Student.new
aStudent.talk # I'm talking.
puts aStudent.sqrt(20.7,3.3) # 4.54972526643248
通过“ include模块名 ” ,一个子类可以得到某个模块的常量和方法。类不能被 include 。
// ------------------------------------------------------------------------------
Extern
include 方法为一个类的所有对象包含某个模块; extend 方法为一个类的某个对象包含某个模块。
#E7.3-2.rb
module Me
def sqrt(num, rx=1, e=1e-10)
num*=1.0
(num - rx*rx).abs
End
end
class Student
end
aStudent=Student.new
aStudent.extend(Me)
puts aStudent.sqrt(93.1, 25) # 9.64883412646315
// ----------------------------------------------------------------------------------
require 和 load
将 Me模块写在文件 E7.4-1.rb中,将 Person类写在文件 E7.4-2.rb中,
这时候 Student类如何使用 Me模块和 Person类呢?这里要用到require方法。
#E7.4-3.rb
require "E7.4-1"
require "E7.4-2"
class Student < Person
include Me
end
aStudent=Student.new
aStudent.talk # I'm talking.
puts aStudent.sqrt(77,2) # 8.77496438739435
还有一个 load 方法与require 方法相对应,也用来包含另一个文件。
#E7.4-4.rb
load "E7.4-1.rb"
class Student
end
aStudent=Student.new
aStudent.extend(Me)
puts aStudent.sqrt(100.1, 12) # 10.0049987506246
require包含文件,只加载一次,遇到同一文件时自动忽略;不同路径下的同名文件会多次加载。
load包含文件,加载多次,即使是相同路径下同一文件。
总结一下:
require,load用于包含文件;include,extend则用于包含模块。
require加载文件一次,load加载文件多次。
require加载文件时可以不加后缀名,load加载文件时必须加后缀名。
require一般情况下用于加载库文件,而load用于加载配置文件。
利用load 多次加载文件的特性,可以用来实现程序的无缝升级和系统的热部署。
程序功能改变了,你只需要重新load 一次,其它代码与它再次交互的时候,这个程序实际上已经不是原来的程序了。
// ----------------------------------------------------------------------------------------------------------------------
再说数组
数组的索引从0开始,一直到数组的长度减去1;负数表示从数组末尾开始的索引;
用一对数字来索引数组,第一个数字表示开始位置,第二数字表示从开始位置起的元素数目。
增加、删除数组元素
Ruby的数组大小是动态的,你能够随时增加、删除数组元素。
print arr.join(", "),"\n" 意思是:将数组arr转换成字符串输出,用", "隔开每个元素,并且换行。
#E8.1-3.rb
arr=[4,5,6]
print arr.join(", "),"\n" #4, 5, 6
arr[4] = "m" #把4号索引位置元素赋值为"m"
print arr.join(", "),"\n" #4, 5, 6, , m
print arr[3] ,"\n" #打印3号索引位置元素 #nil
arr.delete_at(3) #删除3号索引位置元素
print arr.join(", "),"\n" #4, 5, 6, m
arr[2] = ["a","b","c"] #把2号索引位置元素赋值为["a","b","c"]
print arr.join(", "),"\n" #4, 5, a, b, c, m
print arr[2] ,"\n" #打印2号索引位置元素 #abc
arr[0..1] = [7,"h","b"] #把0..1号元素替换为7,"h","b"
print arr.join(", "),"\n" #7, h, b, a, b, c, m
arr.push("b" ) #加入元素"b"
print arr.join(", "),"\n" #7, h, b, a, b, c, m, b
arr.delete(["a","b","c"] ) #删除元素["a","b","c"]
print arr.join(", "),"\n" #7, h, b, m, b
arr.delete("b") #删除所有元素"b"
print arr.join(", "),"\n" #7, h, m
arr.insert(3,"d") #在3号索引位置插入元素"d"
print arr.join(", "),"\n" #7, h, m, d
arr<<"f"<<2 #加入元素"f";加入元素2
print arr.join(", "),"\n" #7, h, m, d, f, 2
arr.pop #删除尾元素
print arr.join(", "),"\n" #7, h, m, d, f
arr.shift #删除首元素
print arr.join(", "),"\n" #h, m, d, f
arr.clear #清空数组arr
print arr.join(", "),"\n" #
// -----------------------------------------------------------------------
迭代器、代码块、闭包
(1..9).each {|i| print i if i<7}>
迭代器each 是数组类的一个方法;大括号{ }里的代码是代码块,简称块。
你可以用大括号{ }将代码组织成块,也可以用 do…end将代码组织成块。
大括号{ }的优先级高于do…end。
#E8.4-1.rb
def one_block
yield
yield
yield
end
one_block { puts "This is a block. " }
运行结果:
This is a block.
This is a block
This is a block
#E8.4-2.rb
def one_block
for num in 1..3
yield(num)
end
end
one_block do |i|
puts "This is block #{i}. "
end
运行结果:
This is block 1.
This is block 2.
This is block 3.
一个块可以接收yield 传来的参数,还可以将结果返回给调用它的方法。
// ***********************************
#E8.4-3.rb
def do_something
yield
end
do_something do
(1..9).each {|i| print i if i<5}>
puts
end
do_something do
3.times { print "Hi!" }
puts
end
运行结果:
>ruby E8.4-3.rb
1234
Hi!Hi!Hi!
>Exit code: 0
// ***********************************
#E8.4-6.rb
class Array
def one_by_one
for i in 0...size
yield(self[i] )
end
puts
end
end
arr = [1,3,5,7,9]
arr.one_by_one {|k| print k , ", "} # 1, 3, 5, 7, 9,
arr.one_by_one {|h| print h*h, ", "} # 1, 9, 25, 49, 81,
闭包
闭包既然是一段代码,也就有自己的状态,属性,作用范围,也就是一个可以通过变量引用的对象,我们称之为过程对象。
一个过程对象用proc创建,用call方法来调用。
闭包作为参数传递给其它方法的例子;
#E8.4-4.rb
def method(pr)
puts pr.call(7)
end
oneProc=proc{|k| k *=3 }
method(oneProc)
运行结果:
>ruby E8.4-4.rb
21
>Exit code: 0
闭包共享其它方法局部变量的例子;
#E8.4-5.rb
def method(n)
return proc{|i| n +=i }
end
oneProc=method(3)
puts oneProc.call(9) #12
puts oneProc.call(5) #17
方法method 返回一个Proc对象,这个对象引用了这个函数的参数:n 。
即使 n这个参数在闭包被调用时已经不在自己的作用域里了,这个闭包还是可以访问 n这个参数,并且和方法method 共同拥有变量 n 。
开始的时候,方法method 的变量 n是3;
oneProc.call(9)的时候,oneProc更新了变量 n,把n=12传回给方法method;
oneProc.call(5)的时候,oneProc取出方法method的变量 n=12,更新为n=17,
传回给方法method的同时,也把n=17作为自己的返回值输出。
// -----------------------------------------------------------------------
元編程
你编写了一个能够生成其它程序的程序,那么,你就在做元编程的工作。
#E9-2.rb
require "E9-1"
class Person < MetaPerson
end
person1 = Person.new
person2 = Person.new
person1.sleep #sleep, sleep, sleep...
person1.running #running, running, running...
person1.modify_method("sleep", "puts 'ZZZ...'")
person1.sleep # ZZZ...
person2.sleep # ZZZ...
在程序 E9-2.rb 中,开始的时候,没有写方法sleep,也没有写方法running,就直接调用了,
后来觉得方法sleep的表达不够形象,就修改了sleep的方法体。
你可能会认为在程序 E9-1.rb 中写了方法sleep和方法running,是不是这样呢?
#E9-1.rb
class MetaPerson
def MetaPerson.method_missing(methodName, *args)
name = methodName.to_s
begin
class_eval(%Q[
def #{name}
puts '#{name}, #{name}, #{name}...'
end
])
rescue
super(methodName, *args)
end
end
def method_missing(methodName, *args)
MetaPerson.method_missing(methodName, *args)
send(methodName)
end
def MetaPerson.modify_method(methodName, methodBody)
class_eval(%Q[
def #{methodName}
#{methodBody}
end
])
end
def modify_method(methodName, methodBody)
MetaPerson.modify_method(methodName, methodBody)
end
end
程序 E9-1.rb是一个能够生成其它程序的程序,你可以在E9-1.rb中将类名改换,只要在其它子类继承就可以了。
其它子类调用方法时,如果是已有的方法,则正常调用;如果是不存在的方法,就由E9-1.rb中的超类自动生成;
如果你觉得方法不合你意,你能够很轻易地修改方法体,这个工作也由E9-1.rb中的超类自动完成。
E9-1.rb中的超类是元编程的一个简单展现。你加入自己修改后的代码,能够使这个程序更加智能化。