我对Ruby(以及一般的编程)很陌生,但我认为有一种方法可以调用所有类对象的属性吗?
class Player
attr_reader :number
def initialize(name, number)
@name = name
@number = number
end
def self.all_numbers
[] << Player.each {|person| person.number}
end
end
guy1 = Player.new('Bill', 23)
guy2 = Player.new('jeff', 18)
我想通过调用类来访问所有对象的数字..
Player.all_numbers
希望回归..
[23, 18]
答案 0 :(得分:5)
您现在遇到的问题是Player
是您的自定义类。它不响应类方法each
。另一个问题是Player
类不知道在它之外创建的实例。
有很多方法可以解决这个问题。我这样做的方法是实现另一个名为Team的类,如此
class Team
def initialize(*players)
@players = players
end
def player_numbers
@players.map { |player| player.number }
end
end
class Player
attr_reader :number
def initialize(name, number)
@name = name
@number = number
end
end
guy1 = Player.new('Bill', 23)
guy2 = Player.new('jeff', 18)
team = Team.new(guy1, guy2)
team.player_numbers
#=> [23, 18]
答案 1 :(得分:2)
在ObjectSpace#each_object
的帮助下写下如下:
在此Ruby进程中为每个活动的非临时对象调用块一次。如果指定了module,则仅为那些匹配(或是其子类)模块的类或模块调用块。返回找到的对象数。永远不会返回立即对象(Fixnums,符号true,false和nil)。
如果没有给出阻止,则返回枚举器。
class Player
attr_reader :number
def initialize(name, number)
@name = name
@number = number
end
def self.all_numbers
ObjectSpace.each_object(self).map(&:number)
end
end
guy1 = Player.new('Bill', 23)
guy2 = Player.new('jeff', 18)
Player.all_numbers
# => [18, 23]
class Player
attr_reader :number
@class_obj = []
def initialize(name, number)
@name = name
@number = number
self.class.add_object(self)
end
def self.add_object(ob)
@class_obj << ob
end
def self.all_numbers
@class_obj.map(&:number)
end
end
guy1 = Player.new('Bill', 23)
guy2 = Player.new('jeff', 18)
Player.all_numbers
# => [23, 18]
答案 2 :(得分:0)
从设计角度来看,使用Team来保存对完整Player对象的引用可能更合适,但您可以使用简单的类变量来执行所需的操作。例如:
class Player
attr_reader :number
@@numbers = []
def initialize(name, number)
@name = name
@number = number
@@numbers << @number
end
def self.all_numbers
@@numbers
end
end
guy1 = Player.new 'Bill', 23
guy2 = Player.new 'jeff', 18
Player.all_numbers
#=> [23, 18]
对于这个简单的用例,这可能就足够了。但是,如果您发现自己试图将整个Player对象填充到Player类变量中,那么您肯定希望找到一个更好的名词(例如团队或玩家)来保存您的集合。
答案 3 :(得分:0)
我只是覆盖new
并将实例保存在类变量中:
class Player
attr_reader :number
def initialize(name, number)
@name = name
@number = number
end
def self.new(*args)
(@@players ||= []) << super
@@players.last
end
def self.all_numbers
@@players.reduce([]) {|arr, player| arr << player.number}
end
end
Player.new('Bill', 23)
Player.new('jeff', 18)
p Player.all_numbers # => [23, 18]
Carpk,我应该解释一些事情:
Player.new('Bill', 23)
会将方法Class#new
与两个参数一起发送到类Player
。通过在此定义self.new
,我将覆盖Class#new
。 self.new
调用super
,它使用Class#new
的参数调用self.new
(除非您只想传递一些参数,否则不需要显式传递参数)。 Class#new
将新的类实例返回给self.new
,它也会返回它,但首先会将其保存在数组@@player
中。(@@players ||= [])
是典型的Ruby技巧。这具有将@@players
设置为等于空数组(如果尚未定义)(为零)的效果,并且如果它已经是数组(空或不是)则保持不变。这是因为@@players ||= []
与@@players = @@players || []
相同。如果@@players => nil
,则变为@@players = []
;否则,@@players
保持不变(永远不会评估[]
)。可爱,嗯? @@players.last
返回Class#new
刚刚返回的类实例,并添加到@@players
的末尾。@@players.reduce([]) {|arr, player| arr << player.number}
创建并返回类实例的数组arr
,然后self.all_numbers
返回。 reduce
的参数是累加器的初始值,这里是块中名为arr
的空数组。注意reduce
和inject
是同义词。Carpk,不要再读了;这只会令人困惑。
我撒了谎。我实际上不会这样做。我建议使用类变量和类方法,因为Carpk是Ruby的新手,可能不会大量使用元编程。我实际上要做的是定义一个类实例变量@players
并制作类new
的{{1}}和all_numbers
单例方法。这样,类Player
的实例将无法轻松访问该变量或这两种方法。为此,只需使用以下内容替换Player
和self.new
的上述定义:
self.all_numbers
Carpk,我警告过你。