实例变量

@ 符号开头的变量就是“实例变量”——这意味着它们属于单独的对象或者类的实例。实例变量不需要提前声明。我可以通过调用类的 new 方法来创建 Dog 类的实例(即 dog 对象)。在这里我创建两个两个 dog 对象(注意,虽然类名是以大写字母开头的,而实例对象名则是以小写字母开头的):

  1. mydog = Dog.new
  2. yourdog = Dog.new

目前,这两只狗还没有名字。所以,接下来我将要做的是调用 set_name 方法来给它们起个名字:

  1. mydog.set_name( 'Fido' )
  2. yourdog.set_name( 'Bonzo' )

现在每只狗都有了名字,但是我以后需要通过某些途径能获知它们的名字。我该怎么办?我不能在对象内部获取 @name 变量,因为每个对象的内部细节只能被它自己所知道。这是纯粹的面向对象的根本:每个对象内部的数据是私有的。每个对象都有其对应的被定义的输入(例如,set_name 方法)和输出接口。只有对象自身才能让它的内部状态变得混乱,外部世界是不能做到的。这被称为“数据隐藏”,并且它是“封装”(encapsulation)原理的一部分。

封装(Encapsulation)
在 Ruby 中,封装并不像最初它出现时的那么严格地被遵守,有一些不好的技巧可以让你使一个对象内部变得混乱。为了清楚起见(并确保你和我不会有恶梦),现在我们默默的了解下面这些语言的特性。

因为我们需要每一只狗都能知道它的名字,让我们给 Dog 类提供一个 get_name 方法:

  1. def get_name
  2. return @myname
  3. end

这里的 return 关键字是可选的。当它被省略时,Ruby 会返回最后一个表达式的值。

为了清楚起见(并为了避免发生意外的结果),我习惯于明确的返回我所期望的值。

最后,我们可以让狗拥有说话的能力。这是最终的类定义:

  1. class Dog
  2. def set_name( aName )
  3. @myname = aName
  4. end
  5. def get_name
  6. return @myname
  7. end
  8. def talk
  9. return 'woof!'
  10. end
  11. end

现在,我们可以创建一个 dog 对象,给它命名、显示它的名字并且让它说话:

  1. mydog = Dog.new
  2. mydog.set_name( 'Fido' )
  3. puts(mydog.get_name)
  4. puts(mydog.talk)
6dogs.rb

我已经在 6dogs.rb 这个文件中编写了这个代码的扩展版本。这个文件也包含了一个类似于 Dog 类的 Cat 类,除过 talk 方法不同,很自然的它的返回值是 miaow 而不是 woof 。

糟糕!这个程序似乎包含一个错误。

名为 someotherdog 的对象从未给它的 @name 变量赋值。幸运的是,在我们要显示这只狗的名字时 Ruby 并不会发生错误,而只会打印“nil”。我们将很快看到一个简单的方式来确保这样的错误不再发生…