#irb(main):036:0> greeter.say_hiHi Pat!=> nil..."> #irb(main):036:0> greeter.say_hiHi Pat!=> nil..."> #irb(main):036:0> greeter.say_hiHi Pat!=> nil..."> #irb(main):036:0> greeter.say_hiHi Pat!=> nil...">
1 | 2 | 3 | 4

二十分钟学会 Ruby

现在我们创建一个 greeter 对象并使用它

irb(main):035:0> greeter = Greeter.new("Pat")
=> #<Greeter:0x16cac @name="Pat">
irb(main):036:0> greeter.say_hi
Hi Pat!
=> nil
irb(main):037:0> greeter.say_bye
Bye Pat, come back soon.
=> nil

创建 greeter 对象后,它会记住名字是 Pat。嗯,如果我们想直接访问名字呢?

irb(main):038:0> greeter.@name
SyntaxError: (irb):38: syntax error, unexpected tIVAR, expecting '('

不行,做不到。

对象内部的秘密

实例变量隐藏在对象内部。它们并没有完全隐藏,你检查对象时能看到它们,也有其他方式可以访问它们,但 Ruby 采用良好的面向对象方法,将数据“稍微”隐藏起来。

那么 Greeter 对象有哪些方法呢?

irb(main):039:0> Greeter.instance_methods
=> [:say_hi, :say_bye, :instance_of?, :public_send,
    :instance_variable_get, :instance_variable_set,
    :instance_variable_defined?, :remove_instance_variable,
    :private_methods, :kind_of?, :instance_variables, :tap,
    :is_a?, :extend, :define_singleton_method, :to_enum,
    :enum_for, :<=>, :===, :=~, :!~, :eql?, :respond_to?,
    :freeze, :inspect, :display, :send, :object_id, :to_s,
    :method, :public_method, :singleton_method, :nil?, :hash,
    :class, :singleton_class, :clone, :dup, :itself, :taint,
    :tainted?, :untaint, :untrust, :trust, :untrusted?, :methods,
    :protected_methods, :frozen?, :public_methods, :singleton_methods,
    :!, :==, :!=, :__send__, :equal?, :instance_eval, :instance_exec, :__id__]

哇。这太多方法了。我们只定义了两个方法。这是怎么回事?好吧,这是 Greeter 对象的 **所有** 方法,一个完整的列表,包括由祖先类定义的那些。如果我们只想列出 Greeter 本身定义的方法,可以通过传递参数 false 来告诉它不包含祖先类,意思是“不想要祖先类定义的方法”。

irb(main):040:0> Greeter.instance_methods(false)
=> [:say_hi, :say_bye]

好吧,这样才像话。所以,让我们看看我们的 greeter 对象可以响应哪些方法

irb(main):041:0> greeter.respond_to?("name")
=> false
irb(main):042:0> greeter.respond_to?("say_hi")
=> true
irb(main):043:0> greeter.respond_to?("to_s")
=> true

所以,它知道 say_hito_s(意思是转换为字符串,这是每个对象默认定义的方法),但它不知道 name

修改类——永不嫌晚

但如果你想查看或更改名字怎么办?Ruby 提供了一种简单的方式来访问对象的变量。

irb(main):044:0> class Greeter
irb(main):045:1>   attr_accessor :name
irb(main):046:1> end
=> [:name, :name=]

在 Ruby 中,你可以重新打开一个类并修改它。这些更改将对你创建的任何新对象生效,甚至对该类的现有对象也有效。所以,让我们创建一个新对象,并玩玩它的 @name 属性。

irb(main):047:0> greeter = Greeter.new("Andy")
=> #<Greeter:0x3c9b0 @name="Andy">
irb(main):048:0> greeter.respond_to?("name")
=> true
irb(main):049:0> greeter.respond_to?("name=")
=> true
irb(main):050:0> greeter.say_hi
Hi Andy!
=> nil
irb(main):051:0> greeter.name="Betty"
=> "Betty"
irb(main):052:0> greeter
=> #<Greeter:0x3c9b0 @name="Betty">
irb(main):053:0> greeter.name
=> "Betty"
irb(main):054:0> greeter.say_hi
Hi Betty!
=> nil

attr_accessor 为我们定义了两个新方法:name 用于获取值,name= 用于设置值。

问候一切,MegaGreeter 概不遗漏!

不过,这个 greeter 并没有那么有趣,它一次只能处理一个人。如果我们有一个 MegaGreeter,可以问候全世界、一个人,或者一整群人呢?

让我们把这个写在一个文件中,而不是直接在交互式 Ruby 解释器 IRB 中。

要退出 IRB,请输入“quit”、“exit”或按 Control-D。

#!/usr/bin/env ruby

class MegaGreeter
  attr_accessor :names

  # Create the object
  def initialize(names = "World")
    @names = names
  end

  # Say hi to everybody
  def say_hi
    if @names.nil?
      puts "..."
    elsif @names.respond_to?("each")
      # @names is a list of some kind, iterate!
      @names.each do |name|
        puts "Hello #{name}!"
      end
    else
      puts "Hello #{@names}!"
    end
  end

  # Say bye to everybody
  def say_bye
    if @names.nil?
      puts "..."
    elsif @names.respond_to?("join")
      # Join the list elements with commas
      puts "Goodbye #{@names.join(", ")}.  Come back soon!"
    else
      puts "Goodbye #{@names}.  Come back soon!"
    end
  end
end


if __FILE__ == $0
  mg = MegaGreeter.new
  mg.say_hi
  mg.say_bye

  # Change name to be "Zeke"
  mg.names = "Zeke"
  mg.say_hi
  mg.say_bye

  # Change the name to an array of names
  mg.names = ["Albert", "Brenda", "Charles",
              "Dave", "Engelbert"]
  mg.say_hi
  mg.say_bye

  # Change to nil
  mg.names = nil
  mg.say_hi
  mg.say_bye
end

将此文件保存为“ri20min.rb”,然后以“ruby ri20min.rb”运行它。输出应为

Hello World!
Goodbye World.  Come back soon!
Hello Zeke!
Goodbye Zeke.  Come back soon!
Hello Albert!
Hello Brenda!
Hello Charles!
Hello Dave!
Hello Engelbert!
Goodbye Albert, Brenda, Charles, Dave, Engelbert.  Come
back soon!
...
...

这个最终的例子中加入了许多新东西,我们可以 深入探讨一下。