在Ruby中重新定义类似乎包含错误的模块

时间:2017-07-20 18:51:58

标签: ruby class module include

我来自Python背景,我试图理解Ruby与Python的多重继承相比如何。具体来说,我使用相同的方法设置了两个模块,以了解super的工作原理。

我包括Mod,然后是Mod2,然后是Mod。但是,A似乎仍在引用Mod2

module Mod
  def foo(x)
    x**2
  end
end
module Mod2
  def foo(x)
    x*2
  end
end

class A
  include Mod
  def foo(x)
    super(x) + 1
  end
end
A.new.foo(5) == 26 # true

class A
  include Mod2
  def foo(x)
    super(x) + 1
  end
end
A.new.foo(5) == 11 # true

class A
  include Mod
  def foo(x)
    super(x) + 1
  end
end
A.new.foo(5) == 26 # false. Is 11

为什么不是第三个A.new.foo(5)返回26

3 个答案:

答案 0 :(得分:1)

在Python中定义class A(object)创建一个type type__name__ A的对象,然后将该对象分配给标签{{1} }。第二个A定义创建一个全新的class A(object)对象,然后将其放入标签A中。

ruby​​中的类不存储在标签中,可以打开它们以添加更多功能。一个很好的例子是type。 Rails在整数上定义2.days。如果没有Rails,days会失败。

上面的3个类定义大致相当于:

2.days

当ruby看到第二个class A include Mod def foo(x) super(x) + 1 end include Mod2 def foo(x) super(x) + 1 end include Mod def foo(x) super(x) + 1 end end 时,它知道include Mod已经包含在课程中并跳过它,从Mod开始foo作为最新定义。

如果您从以后的定义中移除Mod2foo仍然可以访问它:

A

答案 1 :(得分:1)

我认为你可能缺少的是第二个Option Explicit Randomize Dim conn, rst, query, fname, lname, CustID CustID = 000276 '1 query = "SELECT * FROM [Report$] WHERE [ID]= '" & CustID & "'" '2 query = "SELECT * FROM [Report$] WHERE [ID]= '000276' " Set conn = CreateObject("ADODB.Connection") conn.Open "Provider=Microsoft.ACE.OLEDB.12.0;" & _ "Data Source=db2.xlsx;" & _ "Extended Properties='Excel 12.0 Xml;HDR=Yes';" Set rst = CreateObject("ADODB.Recordset") rst.Open query, conn If rst.EOF Then fname = "[NO RECORDS]" lname = "[NO RECORDS]" Else fname = rst("First Name").Value lname= rst("Last Name").Value End If MsgBox("First Name is: " & fname & " and Last Name is: " & lname) 没有重新定义课程,它正在添加它。你被允许打开"一个类在ruby中多次并且(重新)定义你想要的任何东西。那,以及你似乎已经想到的,class A ... end或多或少只是将代码从模块中删除到类定义中的那个位置,除非该模块已被包含在这种情况下它是什么都没有。

你可以在任何课程中做到这一点(无论是否可取)

include

答案 2 :(得分:0)

Ruby通过一次在类/模块的祖先链中搜索一个类/模块来找到super,直到找到它正在寻找的方法的定义。有点像一辆有很多站点的公共汽车,寻找合适的下车地点,但它总是在第一次机会下车。如果它一直到BasicObject并且没有找到它会停止它会引发NoMethodError

当您包含模块时,您将其添加到包含类/模块上方的祖先链中。你可以通过调用Module.ancestors按顺序找到祖先。你可以多次包含同一个模块,但它只会被添加到祖先链一次。考虑一下:

module Mod
  def foo(x)
    x**2
  end
end

module Mod2
  def foo(x)
    x*2
  end
end

class A
  include Mod
  def foo(x)
    super(x) + 1
  end
end

A.ancestors # => [A, Mod, Object, Kernel, BasicObject]

class A
  include Mod2
  def foo(x)
    super(x) + 1
  end
end

A.ancestors # => [A, Mod2, Mod, Object, Kernel, BasicObject]

class A
  include Mod
  def foo(x)
    super(x) + 1
  end
end

A.ancestors # => [A, Mod2, Mod, Object, Kernel, BasicObject]

Mod第二次被包括在血统链中,所以没有新的事情发生。保持不变,super仍然首先点击Mod2。简而言之,你无法覆盖&#34;更新的模块,包括已经存在的旧模块。你可以做其他事情。您可以使用与Mod3中相同的ModOverride定义来定义fooMod,并将其包括在内,或者查看优化Ruby 2.0 How do I uninclude a module out from a module after including it? < / p>

旁注

正如其他答案所指出的那样,如果定义保持不变,则每次都不需要重新定义A#foo