1 | 2 | 3 | 4

20 分钟体验 Ruby

现在让我们创建一个问候对象并使用它

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]

啊,这更像样了。 那么让我们看看我们的问候对象响应哪些方法

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
=> nil

在 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 不会忽略任何事物!

这个问候者并不是很有趣,它一次只能处理一个人。 如果我们有一些 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!
...
...

在这个最后的例子中有很多新东西被引入,我们 可以深入了解一下。