2008年12月17日 星期三

ruby 主要的系统变量以及它们的含义

ruby 主要的系统变量以及它们的含义
转载: RUBY文档中心 http://www.moer.net/ruby/doc/ReadQuestion.asp?QuestionID=114

$! 最近一次的错误信息
$@ 错误产生的位置
$_ gets最近读的字符串
$. 解释器最近读的行数(line number)
$& 最近一次与正则表达式匹配的字符串
$~ 作为子表达式组的最近一次匹配
$n 最近匹配的第n个子表达式(和$~[n]一样)
$= 是否区别大小写的标志
$/ 输入记录分隔符
$\ 输出记录分隔符
$0 Ruby脚本的文件名
$* 命令行参数
$$ 解释器进程ID
$? 最近一次执行的子进程退出状态

Ruby 學習

Ruby语言入门教程v1.0

Ruby 學習

$ 全局变量

@ 实例变量

@@ 类变量, ,类变量在使用前必须要初始化

类名、模块名和常量应该用大写字母开头

字符串是在’’ (单引号), “ “(双引号)之间的代码

数组的下标从0开始。Ruby的数组和其它语言不同,数组的每个元素可以是不同的类型[ 2.4 99“thank you”[ a, b ,c ] 78 ]

区间:

1..5 表示12345

1...5表示1234

// ---------------------------------------------------

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 = "China"

end #初始化方法结束

def talk

puts "my name is "+@name+", age is "+@age.to_s

if @motherland == "China"

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:motherlandattr_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包含文件,加载多次,即使是相同路径下同一文件。

总结一下:

requireload用于包含文件;includeextend则用于包含模块。

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 的变量 n3

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中的超类是元编程的一个简单展现。你加入自己修改后的代码,能够使这个程序更加智能化。