Ruby / Rails:了解ruby getter-setter方法和实例

时间:2013-03-07 20:35:45

标签: ruby-on-rails ruby ruby-on-rails-3 getter-setter

我是ruby和编程的新手,我正在尝试掌握一些关键概念。 鉴于我有一类狗,具有以下特点。

class Dog
  attr_accessor :type, :popularity, :total

  def initialize(type = nil)
    @type = type
  end

  def total_dogs
    Dog.count
  end

  def total
    Dog.where(:type => self.type).size
  end

  def popularity
    total.to_f/total_dogs
  end
end

我想要了解的是,ruby如何通过getter / setter方法将属性持久化到实例。我清楚地知道,如果我实例化一个新实例然后将属性保存到该实例,那么这些属性就与该实例相关联,因为如果我查看该对象,则属性如下所示:

 @dog = Dog.new
 @dog
 => #<Dog:0x007fa8689ea238 @type=nil> 

我很容易理解,当我传递@dog对象时,总是将@type属性作为nil。 但是,我理解的情况是我将这个@dog对象传递给另一个类。就像我做的那样:

 Owner.new(@dog)

当我在所有者类中并且我打电话给@ dog.popularity时,它是如何知道该实例的受欢迎程度的?在运行时,所有方法都被处理,然后该实例总是与当时的值绑定?如果这没有任何意义或我离开,请道歉。

4 个答案:

答案 0 :(得分:6)

当你这样做时

@dog = Dog.new

你做了两件特别的事情

1)为代码当前所在的任何对象创建一个实例变量@dog

2)实例化Dog的新实例(包含其所有方法和属性)并将其引用分配给@dog

@dog是一个变量,恰好指向你在那时创建的Dog实例(“类的实例”,通常意思是“对象”)。您可以将其他变量设置为指向同一个实例,而在Ruby中,这通常是您传递数据的方式。对象包含实例变量,这些实例变量指向更多对象。

使用赋值运算符(即“=”)可以将变量指向任何其他对象。

依次回答你的问题:

  

当我在所有者班级时,我打电话给@ dog.popularity是怎么回事   知道该实例的受欢迎程度值吗?

您必须小心使用Ruby(以及一般的OO语言)来区分描述和问题中的类和对象。 Ruby我假设您指的是Owner类中的一行代码,并且您打算使用所有者对象。我还假设@dog是您添加到所有者的属性。

在这种情况下,Ruby知道因为@dog指向您添加到所有者的Dog对象。每个Dog对象都有自己的所有Dog实例变量的副本。你确实需要在Ruby中注意,因为变量指向到对象,你不是简单地将同一个Dog对象传递给所有的所有者(即它们都有效地共享一只狗)。因此,您需要了解何时创建新实例(通过新实例)以及何时只是处理现有引用。

  

在运行时处理所有方法,然后处理该实例   总是与当时的价值挂钩?

没有。在运行时,基本的Ruby只会执行您编码的赋值。在分配了分配它们的代码之前,实例变量甚至可能不存在。如果你使用attr_reader等方法,那么变量至少会存在(但除非你在初始化期间分配一些东西,否则它们将是nil)

答案 1 :(得分:2)

Niel对此有很好的答案,我只是想补充一点。

数狗:)

你需要一个类变量才能做到这一点..

class Dog
  @@count = 0     # this is a class variable; all objects created by this class share it

  def initialize
    @@count += 1  # when we create a new Dog, we increment the count
  end
  def total
    @@count
  end
end

还有另一种方法可以使用“Class对象的实例变量”,但这是一个高级主题。

访问实例变量

在Ruby中,变量实际上只是对对象/实例的引用。

 > x = 1
 => 1 
 > x.class
 => Fixnum
  > 1.instance_variables
 => [] 

x是对象'1'的引用,它是类Fixnum的一个实例。 '1'对象是Fixnum的一个实例,它不包含任何实例变量。 它与引用新的“Dog”实例没有任何不同。

同样,您可以说x = Dog.new,然后x是对Dog类实例的引用。

class Dog
  attr_accessor :legs   # this defines the 'legs' and 'legs=' methods!
end

x = Dog.new
x.instance_variables
=> []     # if you would assign legs=4 during "initialize", then it would show up here
x.legs = 4      # this is really a method call(!) to the 'legs' method
x.instance_variables   # get created when they are first assigned a value
 => [:legs] 

如果将这样的引用传递给方法调用,或者只传递给另一个类或者只是自己评估它也没关系 - Ruby知道它是一个对象引用,并查看对象内部以及它的继承链如何解决问题

解析方法名称

这只是部分事实:)当解释x.legs时,Ruby检查对象的类继承链中是否有一个方法,它响应该名称'legs'。 它并没有神奇地访问具有相同名称的实例变量!

我们可以通过“attr_reader:legs”或“attr_accessor:legs”定义一个方法'leg',或者自己定义方法。

class Dog
  def legs
     4     # most dogs have 4 legs, we don't need a variable for that
  end
end

x.legs     # this is a method call! it is not directly accessing a :legs instance variable!
 => 4
x.instance_variables
 => []     # there is no instance variable with name ":legs"

如果我们尝试将其作为方法和实例变量实现,则会发生这种情况:))

class Dog
   attr_accessor :legs  # this creates "def legs" and "def legs=" methods behind the scenes
   def legs        # here we explicitly override the "def legs" method from the line above.
      4
   end
end

x = Dog.new
x.legs       # that's the method call we implemented explicitly
 => 4
x.legs = 3   # we can still assign something to the instance_variable via legs=
 => 3
x.legs       # the last definition of a method overrides previous definitions
             # e.g. it overrides the automatically generated "legs" method
 => 4 

attr_accessor :legs只是这样做的简写:

class Dog
  def legs
    @legs
  end 
  def legs=(value)
    @legs = value
  end
end

没有魔法方式实例变量被自动访问。它们总是通过一种方法访问,以后可以覆盖它。

我希望这对你有意义

答案 2 :(得分:0)

创建对象时,无需使用@符号。变量是对象。所以,如果你有多只狗,你可以这样做:

myDog = Dog.new(brown)
yourDog = Dog.new(white)

从那里,你可以说:

yourDog.type #white
myDog.type #brown

你不会做的是:

@dog = Dog.new #myDog
@dog = Dog.new #yourDog

如果您需要一个对象的多个版本,您只需给它们不同的名称。因此,如果您创建多只狗并将它们传递给其他对象,它们将起作用。例如:

假设您的所有者类是:

Class Owner
def initialize(pet)
    puts "my pet is #{pet.type}"
end

然后使用实例变量:

me = Owner.new(myDog) #my pet is brown
you = Owner.new(yourDog) #my pet is white

答案 3 :(得分:0)

“type”和“popular”都是“dog”实例上的方法。他们的定义如下:

class Dog
  # getter
  def type
    @type
  end

  def popularity
    total.to_f/total_dogs
  end
end

这大致相当于:

class Dog
  attr_accessor :type

  def popularity
    total.to_f/total_dogs
  end
end

请注意,attr_accessor只是定义getter方法的快捷方式。如果你自己定义一个方法,那么使用attr_accessor是没有意义的:

class Dog
  attr_accessor :popularity

  # this will override getter defined by attr_accessor
  def popularity
    total.to_f/total_dogs
  end
end

回到你的问题:@ dog.type在@dog上调用type方法,返回它的实例变量; @ dog.popularity在@dog上调用流行度方法,它在运行中进行计算(由你定义)并返回结果。这里没有魔法!