前言
上一篇我们简单介绍了下Ruby,这一节我们开始正式步入Ruby的世界,一探究竟。
Ruby特点
(1)面向对象支持。
(2)动态语言:我们可以修改已经定义过的类,也可以为现有类添加实例方法。
(3)可移植性好:不仅可以运行在UNIX操作系统上,还可以运行在Windows等操作系统上。
(4)弱类型语言:变量无需声明,变量没有类型,变量可以保存任何类型的数据。
(5)支持自动垃圾回收机制:避免我们手动进行垃圾回收。
(6)强大的异常处理机制:保证Ruby程序的健壮性。
(7)简洁的语法:提供正则表达式支持,并支持运算符重载。
(8)清晰的命名规则。
(9)动态载入:运行时取决于所运行的操作系统。
(10)完全免费。
Ruby程序注释
注释有两种形式:
(1)单行注释。
(2)多行注释。
Ruby使用井号(#)表示注释的开始,跟在#号后面直到#号在这行结束的代码将被解释器忽略。如下:
#定义一个方法 def method puts "Hello World" end
以上为单行注释。当然,我们有时需要为代码文档添加注释,这时我们可以用单行注释完成,此时文档代码注释就需要我们通过rdoc命令来提取注释。
Ruby命令规则
(1)以"$"开头的变量为全局变量。
(2)以“@”开头的变量为实例变量。
(3)以“@@”开头的变量为类变量。
(4)以小写字母或者下划线(_)开头的变量为局部变量。
(5)以大写字母开头的变量为常量。
常量
虽然Ruby只要求常量的首字母大写,但是为了提高可读性,一般我们建议对Ruby中的常量全部大写。
class Constant # 定义一个常量 Foo = 5 # 重新赋值 Foo = 6 puts Foo end
一般在其他编程语言中,对常量重新赋值,不会出错,但是在Ruby中,虽然不会抛出错误,但是会给出警告信息: warning: already initialized constant Constant::Foo
(1)对常量不能重新赋值
那么问题来了,常量是否可以定义在任何地方呢?我们看看
def info FOO = 4 puts FOO end
此时会抛出错误: dynamic constant assignment (SyntaxError)
(2)常量只能在类、模块里进行定义,绝不能在方法里定义。
Ruby变量及其作用域
局部变量
局部变量可以被定义在类内部、模块内部或者方法内部,当我们以一个小写字母开头的变量进行赋值时,就表明了一个局部变量。改变量的作用域仅仅属于该类、该模块或者该方法,一旦离开该类、该模块或方法,则此局部变量会自然消失。
# 定义一个类 class Apple # 定义类里局部变量 local = "属于类的局部变量" puts local end # 定义一个方法 def info # 定义方法里的局部变量 local = "属于方法的局部变量" puts local end # 调用方法 info # 定义一个模块 module Vegetable # 定义模块里的局部变量 local = "属于模块里的局部变量" puts local
上述分别在类、方法和模块里面定义了三个局部变量相同的名字,但是三个局部变量互不干扰,它们仅仅在它们对应的类、方法和模块内部有效。
【注意】我们可以定义一个顶层变量即未在上述类、方法以及模块内部,此时此顶层变量就在顶层对象中也就类似于C#中的Object对象中,此时该变量的作用域范围则是整个应用程序。
(1)局部变量不可在内部类和子类中访问。如下:
class Fruit local = "Hello" class Apple puts local end end
此时会报错: undefined local variable or method `local' for Fruit::Apple:Class (NameError)
那么问题来了:要是我们在顶层对象中定义一个顶层变量,那么在类中是否能访问到呢?如下:
local = "Hello" class Apple puts local end
此时同样也会报错,我们上述已经讲述,此顶层变量在顶层对象中,而此Apple则是顶层对象的子类,所以出现上述错误就解释的通了。
那么问题又来了:声明了局部变量后什么时候开始有效呢?我们来看看,测试便知:
class Apple puts local local = "Hello World" end
此时报错如下: undefined local variable or method `local' for Apple:Class (NameError)
当我们在类、模块和方法中声明局部变量时,此时该局部变量就开始生效,随着类、模块和方法的定义结束而结束,但是我们必须在定义之后再使用此局部变量才有效。
(2) 局部变量必须先定义,然后才可使用。
全局变量
由于全局变量可以在任何地方进行访问,所以通常我们应该尽量避免使用全局变量,因为全局变量会引起各个模块之间的耦合。如下
$global = "Hello World" class Apple puts $global end def info puts $global end
我们定义了一个顶层的全局变量,该全局变量既可以在类中访问也可以在方法中访问。
(1)全局变量既可以在类中访问也可以在方法中访问。
那问题来了:全局变量是否必须和局部变量一样,先定义然后才能使用呢?我们看看:
class Apple puts $global end
一运行什么都没有也没出错,什么情况,我们再将代码修改如下:
class Apple puts $global.nil? end
最后打印为 true ,所以我们得出结论。
(2)全局变量无需变量声明,如果引用尚未初始化的全局变量,其值为nil。
实例变量
和静态语言不同,Ruby语言是一门动态语言,因为Ruby的实例变量无需声明,每个实例变量都会在第一次出现时动态加入对象。因此Ruby的实例变量通常在方法中定义类声明,即该实例变量是属于该方法所在类的实例,而不是该方法。我们来看看代码这句话说得到底是什么意思,实践出真知!
class Apple # 定义第一个方法 def info1 # 输出实例变量@ puts @a end # 定义第二个方法 def info2 # 为实例变量赋值 @a = "Hello World" end end # 创建Apple类的实例 apple = Apple.new # 调用方法 apple.info2 apple.info1
即使我们在调用info1方法时此时实例变量@a并未定义,因为方法只有在真正调用时才生效,当我们调用info2方法时,此时会动态为Apple类添加一个@a的实例变量。
说明:在C#和Java中当创建对象时就会一次性为该对象的所有实例变量分配内存空间,但是Ruby却不是这样,因其动态性,在创建对象时该对象没有任何实例变量,直到执行到为实例变量定义时,该对象才动态增加该实例变量。同时它类似于全局变量,实例变量无需显示声明即可使用,若使用一个未定义的实例变量则该实例变量的值为nil。但是实例变量与局部变量还有一点区别就是在于其生命周期,实例变量的生命周期与其对象的生命周期是相同的,只要该类的对象存在,则该对象的实例变量则将一直存在;而局部变量则是随着方法的消亡而消亡(除非使用闭包)。
类变量
类变量从第一次开始赋值的地方开始生效,它既可以在类中定义,也可以在模块中定义,还可以在方法中定义。如下在类中定义类变量代码
class Apple # 在类中定义一个类变量 @@color = "红色" # 直接访问类变量 puts @@color def info # 在方法中访问类变量 puts "苹果的颜色是 "+@@color end end Apple.new.info
类变量和实例变量不同的是,类变量必须先定义,然后才能使用。若引用一个未定义的类变量,则会引发一个uninitialzed class varialbe。
同时我们也是可以在方法中定义类变量,如下:
class Apple def color= (att) # 定义类变量 @@color = att end def color # 访问类变量 @@color end # 此处的@@color依然不可用 puts defined? @@color end #创建两个Apple实例 a1 = Apple.new a2 = Apple.new #依次为两个Apple的实例的@@color变量赋值 a1.color = "红色" a2.color = "绿色" #调用a1的方法来访问@@color变量 puts a1.color
上述打印出 绿色 ,当调用a1.color,此时@@color并未进行定义,此时@@color是为nil,然后将其类变量添加到该实例对象中,
那么问题来了:当调用a1.color = "红色"时,因为此前a2.color = "绿色",此时结果怎么会变成了“绿色”了呢?
此时则会涉及到类变量的一个特性:一个类 、其子类以及它们的实例的同名类变量共享了同一快内存区域即一个类、其子类以及它们的 实例的同名类变量都引用了同一个类变量。
结语
类变量与常量的区别
(1)类变量可以重复赋值(但对常量赋值会发出警告)。
(2)类变量默认是protected的,不能在类外部直接引用(在继承中可以引用或赋值)。
类变量与实例变量的区别
(1)在类范围内定义的类变量,可以在该类的方法中访问,但实例变量不行。
(2)类变量可在子类中引用或者赋值,但实例变量值可在类范围内直接引用或赋值。