访问器

Accessors

访问器

What is an accessor?

访问器是什么?

We briefly discussed instance variables in an earlier chapter, but haven’t done much with them yet.

我们在前面的章节中简要地讨论了实例变量,但是还没有对它们做过多的讨论。

An object’s instance variables are its attributes, the things that distinguish it from other objects of the same class.

对象的实例变量是它的属性,实例变量将它与同类的其他对象区分开来。

It is important to be able to write and read these attributes; doing so requires methods called attribute accessors.

能够读写这些属性是很重要的,这样做需要称为属性访问器的方法。

We’ll see in a moment that we don’t always have to write accessor methods explicitly, but let’s go through all the motions for now. The two kinds of accessors are writers and readers.

稍后我们会看到,我们并不总是需要显式地编写访问器方法,但是现在先让我们来看看所有的动作。这两种访问器分别是writersreaders

  1. ruby> class Fruit
  2. | def set_kind(k) # a writer
  3. | @kind = k
  4. | end
  5. | def get_kind # a reader
  6. | @kind
  7. | end
  8. | end
  9. nil
  10. ruby> f1 = Fruit.new
  11. #<Fruit:0xfd7e7c8c>
  12. ruby> f1.set_kind("peach") # use the writer
  13. "peach"
  14. ruby> f1.get_kind # use the reader
  15. "peach"
  16. ruby> f1 # inspect the object
  17. #<Fruit:0xfd7e7c8c @kind="peach">

Simple enough; we can store and retrieve information about what kind of fruit we’re looking at. But our method names are a little wordy. The following is more concise, and more conventional:

很简单;我们可以储存和获取关于我们正在研究的水果的信息。但是我们的方法名称有点冗长。下面的内容更简洁,更传统:

  1. ruby> class Fruit
  2. | def kind=(k)
  3. | @kind = k
  4. | end
  5. | def kind
  6. | @kind
  7. | end
  8. | end
  9. nil
  10. ruby> f2 = Fruit.new
  11. #<Fruit:0xfd7e7c8c>
  12. ruby> f2.kind = "banana"
  13. "banana"
  14. ruby> f2.kind
  15. "banana"

The inspect method

inspect方法

A short digression is in order. You’ve noticed by now that when we try to look at an object directly, we are shown something cryptic like #.

小小的题外话。你已经注意到当我们试着直接看对象时,我们会看到一些像#<anObject:0x83678>这样神秘的东西。

This is just a default behavior, and we are free to change it.

这只是一个默认的行为,我们可以自由地改变它。

All we need to do is add a method named inspect.

我们所要做的便是添加一个名为inspect的方法。

It should return a string that describes the object in some sensible way, including the states of some or all of its instance variables.

它应该返回一个以某种合理方式描述对象的字符串,包括一些或全部实例变量的状态。

  1. ruby> class Fruit
  2. | def inspect
  3. | "a fruit of the #{@kind} variety"
  4. | end
  5. | end
  6. nil
  7. ruby> f2
  8. "a fruit of the banana variety"

A related method is to_s (convert to string), which is used when printing an object.

一个相关的方法是to_s(转换成字符串),在打印对象时使用该方法。

In general, you can think of inspect as a tool for when you are writing and debugging programs, and to_s as a way of refining program output. eval.rb uses inspect whenever it displays results. You can use the p method to easily get debugging output from programs.

一般来说,你可以将inspect看作是编写和调试程序时的工具,并将to_s作为改进程序输出的一种方法。eval.rb在显示结果时使用inspect。你可以使用p方法轻松地从程序中调试输出。

  1. # These two lines are equivalent:
  2. p anObject
  3. puts anObject.inspect

Making accessors the easy way

使访问器变得简单

Since many instance variables need accessor methods, Ruby provides convenient shortcuts for the standard forms.

由于许多实例变量需要访问器方法,所以Ruby为标准样式提供了方便的快捷方式。

快捷方法 效果
attr_reader :v def v; @v; end
attr_writer :v def v=(value); @v=value; end
attr_accessor :v attr_reader :v; attr_writer :v
attr_accessor :v, :w attr_accessor :v; attr_accessor :w

Let’s take advantage of this and add freshness information.

让我们利用这一点并添加新鲜信息。

First we ask for an automatically generated reader and writer, and then we incorporate the new information into inspect:

首先,我们自动生成的readerwriter,然后我们将这些新信息整合到inspect中:

  1. ruby> class Fruit
  2. | attr_accessor :condition
  3. | def inspect
  4. | "a #{@condition} #{@kind}"
  5. | end
  6. | end
  7. nil
  8. ruby> f2.condition = "ripe"
  9. "ripe"
  10. ruby> f2
  11. "a ripe banana"

More fun with fruit

给水果添加更多乐趣

If nobody eats our ripe fruit, perhaps we should let time take its toll.

如果没有人吃我们成熟的水果,也许我们应该让时间来慢慢腐烂它。

  1. ruby> class Fruit
  2. | def time_passes
  3. | @condition = "rotting"
  4. | end
  5. | end
  6. nil
  7. ruby> f2
  8. "a ripe banana"
  9. ruby> f2.time_passes
  10. "rotting"
  11. ruby> f2
  12. "a rotting banana"

But while playing around here, we have introduced a small problem.

但是在这里玩的时候,我们已经引入了一个小问题。

What happens if we try to create a third piece of fruit now? Remember that instance variables don’t exist until values are assigned to them.

如果我们现在尝试制作第3种水果,会发生什么呢?记住,实例变量在赋值给它们之前是不存在的。

  1. ruby> f3 = Fruit.new
  2. ERR: failed to convert nil into String

It is the inspect method that is complaining here, and with good reason.

这是是在抱怨inspect方法,而且有很好的理由。

We have asked it to report on the kind and condition of a piece of fruit, but as yet f3 has not been assigned either attribute.

我们已经要求它报告一种水果的种类和状况,但是迄今为止,f3还没有被分配到任何一种属性。

If we wanted to, we could rewrite the inspect method so it tests instance variables using the defined? method and then only reports on them if they exist, but maybe that’s not very useful;

如果我们想,我们可以重写inspect方法,以便它使用defined?方法测试实例变,然后只报告它们是否存在,但也许这不是很有用;

since every piece of fruit has a kind and condition, it seems we should make sure those always get defined somehow. That is the topic of the next chapter.

因为每一种水果都有种类和环境,似乎我们应该确保它们总是被定义的。这是下一章的主题。

上一章 异常处理:ensure
下一章 对象初始化