Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby类层次结构中'prepend'的行为_Ruby_Inheritance_Decorator - Fatal编程技术网

Ruby类层次结构中'prepend'的行为

Ruby类层次结构中'prepend'的行为,ruby,inheritance,decorator,Ruby,Inheritance,Decorator,我有一个类Base,还有两个类Derived和Derived2继承自Base。它们各自定义了一个函数foo 我还有一个模块Gen,它是prepend-ed到Base。它也是前置的-ed到Derived2,而不是派生的 当我对Derived2的一个实例调用foo时,结果就好像Gen模块只prepend-ed到Base而不是Derived2一样。这是预期的行为吗 以下是上述场景的代码: module Gen def foo val = super '[' + val + ']'

我有一个类
Base
,还有两个类
Derived
Derived2
继承自
Base
。它们各自定义了一个函数
foo

我还有一个模块
Gen
,它是
prepend
-ed到
Base
。它也是
前置的
-ed到
Derived2
,而不是
派生的

当我对
Derived2
的一个实例调用
foo
时,结果就好像
Gen
模块只
prepend
-ed到
Base
而不是
Derived2
一样。这是预期的行为吗

以下是上述场景的代码:

module Gen
  def foo
    val = super
    '[' + val + ']'
  end
end

class Base
  prepend Gen

  def foo
    "from Base"
  end
end

class Derived < Base
  def foo
    val = super
    val + "from Derived"
  end
end

class Derived2 < Base
  prepend Gen
  def foo
    val = super
    val + "from Derived"
  end
end

Base.new.foo     # => "[from Base]"

Derived.new.foo  # => "[from Base]from Derived"

Derived2.new.foo # => "[from Base]from Derived"

为了帮助您理解,有一个方法
类#祖先
,它告诉您搜索方法的顺序。在这种情况下:

Base.ancestors     # => [Gen, Base, Object, Kernel, BasicObject]
Derived.ancestors  # => [Derived, Gen, Base, Object, Kernel, BasicObject]
Derived2.ancestors # => [Gen, Derived2, Gen, Base, Object, Kernel, BasicObject]
因此,当您对作为所述类的实例的对象调用方法时,将按照该顺序在相应列表中搜索该方法

  • 前置将模块置于该列表的前面
  • 继承将父链放在子链的末尾(不完全是这样,但为了简单起见)
  • super
    只是说“继续遍历链,找到相同的方法”

对于
Base
,我们有两个
foo
的实现,一个在
Base
中,另一个在
Gen
中。将首先找到
Gen
模块,因为模块已预先准备好。因此,在
Base
实例上调用它将调用
Gen#foo
=
[S]
,这也将向上搜索链(通过
super
)=
[from Base]

对于
派生的
,模块没有前缀,我们有继承。因此,第一个发现的实现是,在
Derived
=
Sfrom-Derived
super
中,将搜索来自
Base
的链的其余部分(也就是上面的段落被播放出来)=
[from Base]from-Derived

对于
Derived2
,模块是预先设置的,因此将首先找到那里的方法=
[S]
。然后那里的
super
将在
Derived2
=
[Sfrom-Derived]
中找到下一个
foo
,那里的
super
将再次播放
Base
的情况



编辑:似乎直到最近,
prepend
才会首先在祖先链中搜索,并仅在模块尚未存在时添加模块(类似于
包含
)。更令人困惑的是,如果您首先创建父级,从父级继承,在子级中预加,然后在父级中预加,您将得到更新版本的结果。

我知道
预加
应该如何工作。但是祖先链不是你上面印的。1.
Base.祖先#=>[Gen,Base,Object,Kernel,BasicObject]
2<代码>派生的.祖先#=>[派生的,根,基,对象,内核,基本对象]
3
Derived2.祖先#=>[Derived2,Gen,Base,Object,Kernel,BasicObject]
我现在使用的是Ruby 2.2.4。你知道这种行为改变是在哪个版本发生的吗?@CppNoob我现在下载2.2.5,但它似乎在2.3+之后发生了变化。它没有反映在文档中,我在变更日志中也找不到它。这似乎是一个回归,我会做更多的调查并报告。@CppNoob,是的-它是2.3。0@CppNoob,这是2.3.0之前的“正常”行为。
[Gen,Derived2,Gen,Base,Object,Kernel,BasicObject]
版本附带了2.3.0版本。明确声明,如果它已经存在于链中,则不应预先添加它。所以这似乎是回归,我创造的。
Base.ancestors     # => [Gen, Base, Object, Kernel, BasicObject]
Derived.ancestors  # => [Derived, Gen, Base, Object, Kernel, BasicObject]
Derived2.ancestors # => [Gen, Derived2, Gen, Base, Object, Kernel, BasicObject]