在这两篇文章中:
Can Ruby subclass instance variables _overwrite_ the superclass's (same name)?
人们写的是关于在所有OOP语言中超类和派生类如何不具有单独的对象,并且当您创建派生类的实例时,它也是超类的实例。有一个对象,它同时是两个类。
嗯,问题是我没有得到它?一个对象如何同时成为两个类?如果它们使用相同的名称,那么实例变量如何才能相同呢?
我的意思是我从超类中获取子类获取方法,但我不知道他们如何共享实例变量?
我查看了至少四本Ruby书籍,我发现的所有实例变量都不能通过继承链共享?
有人可以简要解释"实例变量"从子类实际存储在超类?
答案 0 :(得分:3)
这里要理解的关键是:实例变量与当前对象(或实例)相关联,而方法与类相关联。
原因是你不希望为每个创建的单个对象创建新方法,如果它们与该类的所有其他对象具有相同的主体。
另一方面,实例变量必须是每个对象的个体变量,否则在变异值时会有完整的混搭。
<小时/> 考虑到这一点,让我们考虑以下示例:
class Foo
def foo
@var = :foo
end
end
class Bar < Foo
def bar
@var = :bar
end
end
让我们探讨创建新对象时会发生什么:
baz = Bar.new
目前,baz
没有任何实例变量。它只有一个指针,指示“Bar
是我的班级”。
baz.class # => Bar
Foo
或Baz
类没有与@var
关联的任何内容。所以目前,没有人知道@var
。
baz
上调用方法时,会在Bar
祖先链中搜索方法定义:
baz.class.ancestors # => [Bar, Foo, Object, Kernel, BasicObject]
你可以在这里注意一些事项:首先,那里的东西按照继承的顺序出现。其次,Foo
隐含地继承自Object
。第三,模块也可以是链的一部分(如Kernel
)。
baz.bar # => :bar
会在链中找到第一个有方法#bar
并调用它的东西。该值将分配给@var
实例变量,该变量与对象baz
相关联,而不是与Foo
或Bar
类相关联。
baz.foo # => :foo
现在将使用Foo
中的方法定义。但同样,@var
正在更改baz
。
<小时/> 未来阅读的一些相关内容 (因为上面的一些内容因为简单起见并不完全准确):
Class.superclass # => Module
BasicObject#method_missing
答案 1 :(得分:1)
而不是让我们考虑真实的东西。
说你有宠物的概念,并且假设所有宠物都有一个名字。现在让我们说你有PetDog的概念,就像所有宠物都有一个名字一样,但也有一个“品种”。
正如你所看到的,完全合理地想到一个PetDog,作为Pet(它的超类)和PetDog(Pets的子类)
在数学上,您可以将一组具有相似特征的所有对象视为一类,然后子类“包围”超类,并具有更多特征。
class Food
attr_accessor :name
end
class Fruit < Food
attr_accessor :ripeness
end
banana = Fruit.new
banana.ripeness = 0 # very green banana
banana.name = "banana"
steak = Food.new
steak.ripeness = 3 # ERROR... the base class Food does not know about "ripeness"
真实(工作)的例子怎么样?让我们使用react.rb DSL来定义时钟和警报UI组件
Clock组件类是React :: Component :: Base的子类,因此得到很多“状态”,它是基类的一部分。它知道如何渲染到html,它知道如何在事物更新时做出反应等。这个基类的所有部分,以及控制它并使其工作的所有数据都保留在基类中。
另外,Clock ihas有一些特殊属性,即它跟踪@clock变量中的当前时间。它也会每秒更新一次。
然后我们创建一个子类,称为Alarm。
因为Alarm是Clock的子类,它有内部的@clock变量(实际上是时钟类的一部分),和任何其他Clock一样,Alarms每秒更新一次。 这很重要!请注意,正是Clock类初始化了@clock变量,它也是使用时钟更新(重新显示)本身的Clock类。当Alarm继承自Clock时,@clock变量必须保持时钟的一部分,以使其正常运行。
但另外警报使用@clock变量来达到自己的目的,即检查并查看“时间到了”,当它启动时,它可以很好地阻止时钟运行(请注意,即使显示警报后,时钟继续运行,但闹钟没有。
希望这有帮助 - 确保运行示例!
<div id="container"></div>
<script type="text/ruby">
class Clock < React::Component::Base
# a component that displays the time
after_mount do
@clock = every(1) { force_update! }
end
def render
"#{Time.now}"
end
end
class Alarm < Clock
# a kind of clock that notifies its caller when time is up!
param :at, type: Time
param :notify, type: Proc
before_update do
# before_update is a feature of React::Component::Base
# the following code is executed before each update of the Alarm
if Time.now > params.at
params.notify
@clock.stop
end
end
def render
"Alarm will go off in #{(params.at-Time.now).to_i} seconds"
end
end
Element['#container'].render do
div do
# This is react.rb's way of creating a new instance of Clock
# Its shorthand for doing a Clock.new() and a bunch of other stuff
Clock()
br
Alarm(
at: Time.now+10.seconds,
notify: -> { alert ('beep beep beep') }
)
end
end
</script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://rawgit.com/reactive-ruby/inline-reactive-ruby/master/inline-reactive-ruby.js"></script>