【问题标题】:Ruby mixin - accessing module instance variables in class instancesRuby mixin - 在类实例中访问模​​块实例变量
【发布时间】:2017-05-26 12:47:34
【问题描述】:

我对 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>'

似乎@a@b 未初始化。 另外,我不能在action_1 方法中使用“+”运算符。 我错过了什么?

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

【问题讨论】:

  • 这看起来应该是继承模式而不是模块模式。使用继承让这更流畅更实用更明显
  • mixin 继承 is 继承。事实上,include 只是创建了一个类并将该类作为超类。
  • @engineersmnky,实际上我正在尝试做的(未在这段代码中显示)是使用模块获得多重继承。

标签: ruby mixins


【解决方案1】:

实例变量属于实例(这就是它们被称为“实例变量”的原因)。您在这里有三个感兴趣的对象,每个对象都有自己的@b,与其他对象的任何其他@bs 无关:ModuleA 有自己的@b,同样如此ModuleB,和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

【讨论】:

  • 很好的答案,尽管在我看来仍然不如直接的类到类继承模式那么明显。虽然我理解你关于包含超类注入的观点。
  • 非常感谢@Jorg。这是我需要的非常干净的代码。但是,我没有得到您的评论,即上面的代码中有 3 个 @b 实例:一个用于 ModuleA,一个用于 ModuleB,一个用于 ClassA。如果我从 ClassA 实例化对象,如何从包含的模块访问 @b?它不只是在超类的 ClassA 实例上可访问的单个 @b 吗?
  • 另外,还有一条评论,但我可能会提出新问题:如果 classA 实际上通过包含从 2 个模块(假设有额外的 ModuleC)继承,那么如何调用两个超类初始化方法?
  • @PiotrGesicki:实例变量属于对象。每个对象都有自己的一组实例变量,这些变量对该特定对象完全私有。对象a 的实例变量@foo 与对象b 的实例变量@foo 完全分离。在您的代码中,有三个不同的对象,它们都有一个实例变量@bModuleAModuleBinstA 都有一个名为@b 的实例变量。但它们是三个不同的对象。他们彼此没有任何关系。您将ModuleA 的实例变量@b 设置为某个值的事实......
  • ... 对对象ModuleB 的实例变量@b 或对象@b 的实例变量instA 绝对没有任何影响。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-05-28
  • 2015-12-01
  • 2014-09-21
  • 2017-06-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多