[Dive into Ruby] Ruby Basic 变量、常量以及对象

10/6/2017 posted in  编程语言 comments

上一篇博客主要介绍了一下 Ruby 的一些语法糖,以及作为脚本语言 Ruby 的优势所在。这一篇则开始正式介绍 Ruby 的基础语法,以及语言细节。由于 Ruby 是完全面向对象式的,因此,有 Java 基础的人能够很快的了解到 Ruby 的大部分特性,但是有一些是 Ruby 特有的,或者 Java 有而 Ruby 不支持的,这一部分会更加特别说明。

Ruby 中的对象

在 Ruby 中,对象是表现数据的最基本单位。所有的对象都由 BaseObject 派生,而大部分的对象又是由 BaseObject 的子类 Object 派生。BaseObject 与 Object 类分别实现了一些所有的对象均需要的方法,例如 Object.nil? 方法(用以判断是否为空,返回 true 或者 false)等。
Ruby 中内置了一些常用的对象类型供我们使用,例如数值对象、字符串对象、数组对象、散列对象、时间对象、文件对象,甚至正则表达式对象,等等。
接下来会介绍一些比较常见的对象以及常用的方法。
在介绍对象之前,先介绍一些关于变量和常量的基本知识(与其它编程语言类似)。

变量与常量

与其它编程语言类似的,Ruby 中对变量和常量加以区分。何为变量(variable)?即变化的东西,定义一个人的年龄,age = 10,这是一个变量,因为人的年龄是会变的。何为常量(constant)呢?即不变的量,如定义一本书的序列号 ISBN="SN12345",在程序中是默认不会改变的。
Ruby 中对于变量和常量的命名有着一些默认的规则,变量一般使用下划线命名法或者驼峰命名法,如 agestudentNumber,这样都是可以的。但通常情况下,一般的变量使用下划线命名法,而对类的实例使用驼峰命名法,这样能够更加清楚的区分变量的类型。Ruby 中的常量使用全大写命名,中间加下划线,例如 MAX_NUMBER
同时 Ruby 中又内置了一些全局的常量,例如 RUBY_VERSION,可以方便的在程序中调用来判断当前的环境等等。
注意, Ruby 中的常量并非真正的不可改变。例如这样一段代码。

  NAME = "HE" # => HE
  p NAME # => HE
  NAME = "SHE" # => warning: already initialized constant NAME, warning: previous definition of NAME was ...
  p NAME # => SHE

在试图修改常量时,Ruby会报出一个 warning,表明你正在修改一个常量的值,以及常量的定义位置。但同时也会默默的修改掉常量的值。

变量的类型

Ruby 中的变量分成四种类型,分别是局部变量(local variable)、全局变量(global variable)、实例变量(instance variable)、类变量(class variable)。
Ruby 中对不同变量的命名也是有着默认的规范的。
局部变量以小写字母或者_开头,
全局变量以$开头,
实例变量以@开头,
类变量以@@开头。

还有一种类型,叫做 伪变量,例如 nil\self\true\false 等等。伪变量是 Ruby 中预先定义好的表示某些特定值的特殊变量,即使我们在程序中人为的去改变,也不会生效。伪变量虽然看着像是变量,但是实际行为与变量有很多不同的地方。

要怎样去理解这些类型呢,其实很简单,看这些变量的作用域,以及谁来调用就可以了。
对于局部变量和全局变量,可以参考这样一段代码。

  $name = "Ruby"
  
  def hello name
    greeting = "hello"
    puts "#{greeting} #{name}"
  end
  
  my_name = "Cray"
  hello my_name # => hello Cray
  hello $name  # => hello Ruby

在这段代码中, $name是一个全局变量,在这个例子中并没有体现出它作为全局变量的能力,但是当这段代码被其它代码调用时,整个程序中共享着同一个全局变量 $name,因此可以在其它地方修改,调用。
my_name是一个局部变量,这意味着它只能在整个程序的这个部分使用,如果你在另一个地方使用my_name,你用的变量跟这个完全没有任何关系。
对于 greeting 这个变量,则是 hello() 这个函数的一个局部变量,只能在函数内使用,函数外无法调用。
注意,通常不建议在程序中过多的使用全局变量,因为这样会无法保证是否有其它地方修改过这些变量,会给 debug 带来非常大的麻烦,而且在多线程调用的时候,也无法保证全局变量的共享问题。因此,给自己省点麻烦,除非迫不得已,否则尽量不用。

那么对于实例变量和类变量呢?写过 Java 的人应该都知道,Java 中的变量有 staticnon static的区别, static 的变量,可以通过类名.对象名来使用,例如 Math.PI,而non static的变量,则需要创建一个类的实例,通过实例来调用。Ruby 中的实例变量与类变量与 Java 中无异,实例变量需要通过类的实例去调用,而类变量则是通过类自身去调用。这就是它们之间的差别。
同样的区别也会发生在实例方法与类方法中,后面会详细介绍。

好的,介绍完了变量类型,接下来继续介绍对象。

Ruby 中常用的对象

在编程语言中,最基础的功能就应当是数的表达与运算,整型数、浮点数,加、减、乘、除等等。在 Ruby 中使用数值的方法与其它语言无异,但是有一点需要注意,在 Ruby 中,以加法为例:

a = 3
b = 4
c = a + b

其中 c = a + b,这里的 +,其实是 a.add(b) 的一个语法糖,等效于调用对象 a 的方法。

还有一点需要注意的是,在 Ruby 中,1 == 1.0 的返回值是 true,因为这里的==方法被重写了,在这里数值的 == 方法实现的是值比较,所以返回的是 true,而如果是 eql? 方法,1.eql? 1.0,返回的则是 falseequals? 方法与 eql? 方法是不能够被子类所重写的,永远比较的是对象的引用,而不是值。

同样的,字符串对象的使用也很简单。在字符串对象中可以通过 #{} 来注入变量与方法。

name = "Ruby"
greeting = "hello #{name}"
  
def hello name
return "hello #{name}"
end
  
puts "Welcome, #{hello 'Ruby'}"

Ruby 中的数组对象和散列对象内置了一些方便方法,如迭代器,排序等等。例如向数组中添加一个新的元素。

arr = []
arr << "Andy"
arr.append "Bob"

# 创建一个新的hash
hash = Hash.new
hash[:name] = "Andy"
hash[:age] = 19
hash[:grade] = 3

puts hash[:name]

其它的像时间对象、文件对象的使用方法也都比较简单,可以通过API文档查询使用方法,这里就不过多介绍了。

关于 Ruby 中的变量常量以及对象就介绍这么多,下一篇会开始介绍 Ruby 中的控制流,if unless when while until等等,再后面会介绍 Ruby 中方法,以及类(class)与类的继承(inheritance),还有模块(module)相关的概念。