2010-02-09 54 views
2

我想在一个模块中定义一个静态变量和方法,这个模块会被许多类扩展/使用。下面的示例演示:我与模块有一个问题

module Ammunition 
    def self.included(base)  
    base.class_eval("@@ammo = [bullets]") 
    end 

    def unload 
    p @@ammo #<-- doesn't work 
    end 
end 

class Tank 
    include Ammunition 
    @@a += [shells] 
end 

class Airplane 
    include Ammunition 
    @@a += [missiles, photon_torpedoes] 
end 

Tank.new.unload 
Airplane.new.unload 

这不起作用,因为弹药不知道如何评价在类的上下文@@弹药出于某种原因(我原以为模块将表现就像一个包括文件)。我必须将'卸载'复制到每个类,我现在正在执行,但我想干掉它b/c我有许多其他方法添加到模块。

对此提出建议?合理的解决方案是在类的上下文中评估“卸载”而不是模块(但是如何在Ruby中执行此操作?)

谢谢!

+0

1.为什么Ruby on Rails标记? 2.你的模块被称为'弹药'('弹药'?),但是你后来'包含可压缩的' - 这根本不在这里。 3.你的代码试图做什么并不是很清楚。说明有所帮助,但不完全。 – Telemachus 2010-02-09 00:59:44

+0

谢谢Squeegy - 你设法回答我错综复杂和措辞不佳的/编辑的问题(道歉没有措辞更好)!我真正的问题是,我试图编写一个模块,用于json打包一堆与多态关联绑定在一起的模型。我以设置attr_reader的方式完成了这个任务。 – ambertch 2010-02-10 00:52:08

回答

4

类变量可以奇怪地工作,这种使用表明关闭。 @@ammo的范围是什么? Ammunition还是Tank有它自己的副本吗?事实证明,@@ammo是由模块作用域,并且包含它的类可以简单地访问它。

module Ammunition 
    def self.included(base)  
    base.class_eval do 
     puts "@@ammo was: #{defined?(@@ammo) ? @@ammo.join(',') : 'nil'}" 
     @@ammo = ['bullets'] 
     puts "@@ammo is now: #{@@ammo}" 
     puts '---' 
    end 
    end 

    def unload 
    @@ammo 
    end 
end 

class Tank 
    include Ammunition 
    @@ammo += ['shells'] 
end 

class Airplane 
    include Ammunition 
    @@ammo += ['missiles', 'photon_torpedoes'] 
end 

puts "Tank unloaded: #{Tank.new.unload.join(', ')}" 
puts "Airplane unloaded: #{Airplane.new.unload.join(', ')}" 

这产生:

@@ammo was: nil 
@@ammo is now: bullets 
--- 
@@ammo was: bullets,shells 
@@ammo is now: bullets 
--- 
Tank unloaded: bullets, missiles, photon_torpedoes 
Airplane unloaded: bullets, missiles, photon_torpedoes 

Tank包括模块时,它设置@@ammo从零到在它的子弹的阵列。当Airplane包含该模块时,它会覆盖我们刚刚设置的弹药值。


这里是你想要做

module Ammunition 
    def self.included(base)  
    base.class_eval do 
     include Ammunition::InstanceMethods 
     extend Ammunition::ClassMethods 
     @ammo = ['bullets'] 
    end 
    end 

    module ClassMethods 
    def ammo 
     @ammo 
    end 
    end 

    module InstanceMethods 
    def unload 
     self.class.ammo.join(',') 
    end 
    end 
end 

class Tank 
    include Ammunition 
    @ammo += ['shells'] 
end 

class Airplane 
    include Ammunition 
    @ammo += ['missiles', 'photon_torpedoes'] 
end 

puts "Tank unloaded: #{Tank.new.unload}" 
puts "Airplane unloaded: #{Airplane.new.unload}" 

类可以有实例变量是什么,他们的范围更容易理解。并且将你的模块分成实例和类方法可以让你为两者提供功能。这段代码生成以下输出

Tank unloaded: bullets,shells 
Airplane unloaded: bullets,missiles,photon_torpedoes 
+0

绝对要走的路 - 应该使用attr_reader:ammo作为弹药吸气剂方法,而不是手动定义它。 – bensie 2010-02-09 05:53:27

+0

谢谢Squeegy - 你设法回答了我的复杂和措辞不佳/编辑的问题(道歉没有措辞更好)!我真正的问题是,我试图编写一个模块,用于json打包一堆与多态关联绑定在一起的模型。我以设置attr_reader的方式完成了这个任务。 – ambertch 2010-02-10 00:51:32

+0

很高兴提供帮助。我没有使用'attr_reader'的原因是因为它通常在类作用域中定义,但会影响实例作用域中的实例变量,因此可能会造成混淆。并且通过模块的'extend'来完成对班级的操作。但是由于这种方式并不常用,所以它可能会给你关于它实际范围的变量的错误想法。所以只是我喜欢的风格偏好。 – 2010-02-10 01:32:45

0

的几个问题:

(1)模块名ammunition必须以大写字母开头 - Ammunition

(2)你包括Packagable到您的类,但我假设你的意思Ammunition? (3)所有变量 - missiles,photonphoton_torpedos都未定义,所以您的代码实际上不会运行。

我建议你先修正这段代码:)但是,作为一个例外,类变量@@myvar被认为是绝大多数的Rubyists中的一种。

3

嗯,首先...解释@@变量如何正确工作是一个非常好的主意。

@@变量是可以在实例上下文来访问类变量,例如说:

class Klass 

    def my_klass_variable=(str) 
    # self here points to an instance of Klass 
    @@my_klass_variable = str 
    end 

    def my_klass_variable 
    @@my_klass_variable 
    end 

end 

Klass.new.my_klass_variable = "Say whaat?" 
# Note this is a different instance 
Klass.new.my_klass_variable # => "Say whaat?" 

然而,这种类型的变量也将招致以下结果:

class OtherKlass < Klass; end 

Klass.new.my_klass_variable = "Howdy" 
# Note this is a different instance, and from the child class 
OtherKlass.new.my_klass_variable # => "Howdy" 

疯狂行为确实。另一种创建类变量的方法是在以self.开头的方法上定义实例变量。例如:

class Klass 
    def self.my_class_method 
    @class_var = "This is a class var" 
    end 
end 

为什么@也用于类变量呢?请记住Klass在这是Class类的实例,这将具有它自己的实例变量,那末端将是类实例变量Klass

Klass.class # => Class 
Klass.instance_of?(Class) # => true 
k = Klass.new 
k.class # => Klass 
k.instance_of?(Klass) # => true 

这是类变量更安全(因为他们将有变量的一个副本,而不是共享一个与子类也一样),并会表现为你期望使用你的榜样时的行为:

module Ammunition 

    def self.included(base)  
    base.class_eval do 
     @ammo = [bullets] # where bullets come from any way? 
    end 
    end 

    def self.unload 
    p @ammo 
    end 

end 

class Tank 
    include Ammunition # Probably you meant that instead of Packagable 
    @ammo += [shells] # I think you meant @ammo instead of @a 
end 

class Airplane 
    include Ammunition # Probably you meant that instead of Packagable 
    @ammo += [missiles, photon_torpedoes] # I think you meant @ammo instead of @a 
end 

如指出他人将无法正常工作此代码(给没有炮弹,导弹,也没有photo_torpedoes),但我认为你可以弄清楚如何使自己的工作。