首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Ruby/Rails:了解ruby getter-setter方法和实例

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

Stack Overflow用户
提问于 2013-03-08 04:35:45
回答 4查看 7.8K关注 0票数 1

一般来说,我是ruby和编程的新手,我正在努力掌握一些关键概念。假设我有一个Dog类,具有以下特征。

代码语言:javascript
复制
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方法将属性持久化到实例的。我很清楚,如果我实例化一个新实例,然后将属性保存到该实例,这些属性将绑定到该实例,因为如果我查看对象,这些属性看起来是这样的:

代码语言:javascript
复制
 @dog = Dog.new
 @dog
 => #<Dog:0x007fa8689ea238 @type=nil> 

我很容易理解,当我传递@dog对象时,它的@type属性总是为nil。然而,如果我将这个@dog对象传递给另一个类,我就很难理解这种情况。就像如果我这么做了:

代码语言:javascript
复制
 Owner.new(@dog)

当我在owner类中调用@dog.popularity时,它如何知道该实例的流行度的值?在运行时,是否所有的方法都被处理,然后该实例总是绑定到当时的值?如果这没有任何意义,或者我说错了,我很抱歉。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2013-03-08 04:59:19

当你这样做的时候

代码语言:javascript
复制
@dog = Dog.new

你要做两件重要的事

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

2)实例化一个新的Dog实例(以及它的所有方法和属性),并将对它的引用分配给@dog

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

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

依次回答你的问题:

当我在owner类中调用@dog.popularity时,

如何知道该实例的流行度的值?

在Ruby (以及一般的面向对象语言)中,你必须小心区分描述和问题中的类和对象。Ruby我假设你引用的是Owner类中的一行代码,并且你打算让它与owner对象一起工作。我还假设@dog是您添加到Owner的属性。

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

在运行时是否处理了所有的方法,然后该实例总是绑定到当时的值?

不是的。在运行时,basic Ruby将只执行您编写的赋值。在赋值实例变量的代码运行之前,实例变量可能根本不存在。如果你使用attr_reader等方法,那么变量至少会存在(但是除非你在初始化时赋值,否则变量将是空的)

票数 6
EN

Stack Overflow用户

发布于 2013-03-08 05:56:07

Niel对此有一个很好的答案,我只是想补充一些东西。

计数狗 :)

您需要一个类变量来执行此操作。

代码语言:javascript
复制
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

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

访问实例变量的

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

代码语言:javascript
复制
 > x = 1
 => 1 
 > x.class
 => Fixnum
  > 1.instance_variables
 => [] 

X是对对象“1”的引用,该对象是Fixnum类的实例。“%1”对象是Fixnum的实例,它不包含任何实例变量。它与对新的"Dog“实例的引用没有任何不同。

类似地,您可以说x = Dog.new,那么x就是对Dog类实例的引用。

代码语言:javascript
复制
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检查对象的类继承链中是否有一个方法,它响应那个名字“腿”。它不能神奇地访问同名的实例变量!

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

代码语言:javascript
复制
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"

如果我们试图将它实现为一个方法和一个实例变量,就会发生这种情况::)

代码语言:javascript
复制
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只是实现这一点的一种简写符号:

代码语言:javascript
复制
class Dog
  def legs
    @legs
  end 
  def legs=(value)
    @legs = value
  end
end

没有什么神奇的方法可以自动访问实例变量。它们总是通过一个方法来访问,这个方法可以在以后被覆盖。

我希望你能明白这一点

票数 2
EN

Stack Overflow用户

发布于 2013-03-08 04:56:50

创建对象时,不需要使用@符号。变量就是对象。所以如果你有多条狗,你会这样做:

代码语言:javascript
复制
myDog = Dog.new(brown)
yourDog = Dog.new(white)

从那里,你可以说:

代码语言:javascript
复制
yourDog.type #white
myDog.type #brown

你不会做的事情是:

代码语言:javascript
复制
@dog = Dog.new #myDog
@dog = Dog.new #yourDog

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

假设你的所有者类是:

代码语言:javascript
复制
Class Owner
def initialize(pet)
    puts "my pet is #{pet.type}"
end

那么使用实例变量将是:

代码语言:javascript
复制
me = Owner.new(myDog) #my pet is brown
you = Owner.new(yourDog) #my pet is white
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15281215

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档