Ruby mixin-在类实例中访问模块实例变量

Ruby mixin-在类实例中访问模块实例变量,ruby,mixins,Ruby,Mixins,我对Ruby还很陌生,似乎仍然对mixin和在类中包含模块感到困惑。我希望能够访问类中模块中定义的实例变量(@)。 我有以下代码: module ModuleB attr_reader :b def ModuleB.initialize(browser) puts "initialize from ModuleB" @browser = browser @b = 5 end end module ModuleA attr_reader :a inc

我对Ruby还很陌生,似乎仍然对mixin和在类中包含模块感到困惑。我希望能够访问类中模块中定义的实例变量(@)。 我有以下代码:

module ModuleB
  attr_reader :b

  def ModuleB.initialize(browser)
    puts "initialize from ModuleB"
    @browser = browser
    @b = 5
  end
end

module ModuleA
  attr_reader :a
  include ModuleB

  def ModuleA.initialize(browser)
    ModuleB.initialize(browser)
    puts "initialize from ModuleA"
    @browser = browser
    @a = @b
  end

  def action_1
    @a = @b + 1
    return @a
  end
end

class ClassA
  include ModuleA
  def initialize(browser)
    ModuleA.initialize(browser)
    @browser = browser
    puts 'initialize - method in ClassA'
    @c = @a
    @d = @b
    puts "a = #{@a}"
    puts "b = #{@b}"
    puts "c = #{@c}"
    puts "d = #{@d}"
  end

end

s = 'hello'
instA = ClassA.new(s)
puts instA.action_1
这是我得到的结果:

initialize from ModuleB
initialize from ModuleA
initialize - method in ClassA
a =
b =
c =
d =
mixin_example2.rb:23:in `action_1': undefined method `+' for nil:NilClass (NoMethodError)
        from mixin_example2.rb:46:in `<main>'
从模块B初始化
从ModuleA初始化
ClassA中的initialize-method
a=
b=
c=
d=
mixin_example2.rb:23:in'action_1':nil:NilClass(NoMethodError)的未定义方法“+”
来自mixin_示例2.rb:46:in`'
似乎
@a
@b
未初始化。 另外,我不能在
action\u 1
方法中使用“+”运算符。 我错过了什么


抱歉,如果我重复了可能已经提出的问题,但到目前为止我还没有找到答案。

实例变量属于实例(这就是为什么它们被称为“实例变量”)。这里有三个感兴趣的对象,每个对象都有自己的
@b
,而与其他对象的任何其他
@b
无关:
模块a
有自己的
@b
,就像
模块b
一样,
instA
也有自己的
@b

下面是一个更合理的实现方法:

module ModuleB
  def initialize(browser)
    puts "initialize from ModuleB"
    @browser = browser
    @b = 5
  end
end

module ModuleA
  include ModuleB

  def initialize(browser)
    super
    puts "initialize from ModuleA"
    @a = @b
  end

  def action_1
    @a = @b + 1
  end
end

class ClassA
  include ModuleA

  def initialize(browser)
    super
    puts 'initialize - method in ClassA'
    @c = @a
    @d = @b
    puts "a = #@a"
    puts "b = #@b"
    puts "c = #@c"
    puts "d = #@d"
  end
end

s = 'hello'
instA = ClassA.new(s)
# initialize from ModuleB
# initialize from ModuleA
# initialize - method in ClassA
# a = 5
# b = 5
# c = 5
# d = 5
#=> #<ClassA:0x007f8b5f12e110 @a=5, @b=5, @browser="hello", @c=5, @d=5>

puts instA.action_1
# 6
模块b
def初始化(浏览器)
将“从模块B初始化”
@浏览器=浏览器
@b=5
结束
结束
模模A
包含模块B
def初始化(浏览器)
超级的
将“从模块A初始化”
@a=@b
结束
def行动1
@a=@b+1
结束
结束
甲级
包含模块a
def初始化(浏览器)
超级的
将“初始化-方法放入类A”
@c=@a
@d=@b
把“a=#@a”
放置“b=#@b”
放入“c=#@c”
放置“d=#@d”
结束
结束
s=‘你好’
instA=ClassA.new(s)
#从ModuleB初始化
#从ModuleA初始化
#ClassA中的initialize-method
#a=5
#b=5
#c=5
#d=5
#=> #
将instA.action_1
# 6

这似乎应该是一种继承模式,而不是模块模式。不过,使用继承可以使这一过程更顺畅、更有效、更明显。mixin继承就是继承。事实上,
include
只是创建一个类并使该类成为超类。@engineersmnky,事实上,我正试图做的(在这段代码中没有显示)是使用模块获得多个继承。这是一个很好的答案,尽管在我看来,仍然没有直接的类到类继承模式那么明显。虽然我理解你关于包含超类注入的观点。非常感谢@Jorg。这是我需要的非常干净的代码。然而,我没有得到你的评论,上面的代码中有3个@b实例:一个用于ModuleA,一个用于ModuleB,一个用于ClassA。如果我从ClassA实例化对象,我如何从包含的模块访问@b?它不只是一个从超类在ClassA实例上可访问的@b吗?另外,还有一条评论,但我可能会提出一个新问题:如果ClassA实际上通过includes从2个模块(比如说有额外的ModuleC)继承,那么如何调用这两个超类初始化方法?@PiotrGesicki:实例变量属于对象。每个对象都有自己的实例变量集,这些变量对特定对象是完全私有的。对象
a
的实例变量
@foo
与对象
b
的实例变量
@foo
完全分离。在代码中,有三个不同的对象,它们都有一个实例变量
@b
ModuleA
ModuleB
,和
instA
都有一个名为
@b
的实例变量。但它们是三个不同的对象。他们彼此无关。将
ModuleA
的实例变量
@b
设置为某个值……这一事实对对象
ModuleB
的实例变量
@b
或对象
instA
的实例变量
@b
绝对没有任何影响。