我正在尝试在模块中定义静态变量和方法,这些变量和方法将被许多类扩展/使用。以下示例演示:
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
这不起作用,因为弹药由于某种原因不知道如何在类的上下文中评估@@ ammo(我原来认为模块的行为就像包含文件一样)。我必须将'卸载'复制到每个类,我现在正在做,但我想干它b / c我还有很多其他方法可以添加到模块中。
连连呢?合理的解决方案是在类的上下文中评估'unload'而不是模块(但是如何在Ruby中执行此操作?)
谢谢!
答案 0 :(得分:4)
类变量可以奇怪地工作,这个用法显示了off。 @@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
从nil设置为包含项目符号的数组。当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
答案 1 :(得分: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
类的实例,它将拥有自己的实例变量,最后将是{{1的实例的类变量}}
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),但我认为你可以弄明白如何让它自己运作。
答案 2 :(得分:0)
一些问题:
(1)模块名称ammunition
必须以大写字母Ammunition
(2)您在课程中加入Packagable
,但我认为您的意思是Ammunition
?
(3)您的所有变量 - missiles
,photon
和photon_torpedos
都未定义,因此您的代码实际上并未运行。
我建议你先修复这段代码:)但是除此之外,类变量@@myvar
在大多数Rubyists中都被认为是禁忌。