一般来说,我是ruby和编程的新手,我正在努力掌握一些关键概念。假设我有一个Dog类,具有以下特征。
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)当我在owner类中调用@dog.popularity时,它如何知道该实例的流行度的值?在运行时,是否所有的方法都被处理,然后该实例总是绑定到当时的值?如果这没有任何意义,或者我说错了,我很抱歉。
发布于 2013-03-08 04:59:19
当你这样做的时候
@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等方法,那么变量至少会存在(但是除非你在初始化时赋值,否则变量将是空的)
发布于 2013-03-08 05:56:07
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还有另一种方法可以使用“类对象的实例变量”来实现这一点,但这是一个有点高级的主题。
访问实例变量的
在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检查对象的类继承链中是否有一个方法,它响应那个名字“腿”。它不能神奇地访问同名的实例变量!
我们可以通过执行"attr_reader :legs“或"attr_accessor :legs",或者通过自己定义方法来定义一个方法”legs“。
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没有什么神奇的方法可以自动访问实例变量。它们总是通过一个方法来访问,这个方法可以在以后被覆盖。
我希望你能明白这一点
发布于 2013-03-08 04:56:50
创建对象时,不需要使用@符号。变量就是对象。所以如果你有多条狗,你会这样做:
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 whitehttps://stackoverflow.com/questions/15281215
复制相似问题