Ruby class 变量实例变量bug
Ruby class variable instance variable bug
Game
有一个包含十个 Frame
个实例的数组
class Frame
attr_accessor :rolls
def initialize
@rolls = ""
end
end
class Game
attr_accessor :frames
def initialize
@frames = Array.new(10, Frame.new)
end
def print_frames
@frames.each_with_index do |frame, idx|
p "Frame ##{idx+1}: #{frame.rolls}"
end
end
end
game = Game.new
rolls = [5, 5, 3, 7, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2]
curr = 0
rolls.each_with_index do |roll|
game.frames[curr].rolls << roll.to_s
if game.frames[curr].rolls.size == 2
curr += 1
end
end
p "Total rolls: #{rolls.size}"
p game.print_frames
我希望打印 10 行,每行都有一个 frame id 和一个由 2 个数字组成的字符串
但是,返回以下内容
"Total rolls: 20"
"Frame #1: 55374000000000000022"
"Frame #2: 55374000000000000022"
"Frame #3: 55374000000000000022"
"Frame #4: 55374000000000000022"
"Frame #5: 55374000000000000022"
"Frame #6: 55374000000000000022"
"Frame #7: 55374000000000000022"
"Frame #8: 55374000000000000022"
"Frame #9: 55374000000000000022"
"Frame #10: 55374000000000000022"
[#<Frame:0x0000565402e40528 @rolls="55374000000000000022">, #<Frame:0x0000565402e40528 @rolls="55374000000000000022">, #<Frame:0x0000565402e40528 @rolls="55374000000000000022">, #<Frame:0x0000565402e40528 @rolls="55374000000000000022">, #<Frame:0x0000565402e40528 @rolls="55374000000000000022">, #<Frame:0x0000565402e40528 @rolls="55374000000000000022">, #<Frame:0x0000565402e40528 @rolls="55374000000000000022">, #<Frame:0x0000565402e40528 @rolls="55374000000000000022">, #<Frame:0x0000565402e40528 @rolls="55374000000000000022">, #<Frame:0x0000565402e40528 @rolls="55374000000000000022">]
实例变量的作用类似于 class 帧之间共享的变量。所有 20 个卷数都连接在一起,而不是每个帧拥有一对。
代码有什么问题?是因为 Game
或 Frame
对象没有正确实例化吗?
方法 Array.new 定义为 new(size=0, default=nil) 这意味着第二个参数将是数组中所有对象的值,默认值。
这就是为什么对于您的情况,所有 10 个对象都是相同的。
https://ruby-doc.org/core-2.7.0/Array.html#method-c-new
这段代码可以帮助您解决
@frames = []
10.times {|i| @frames.push(rand) }
=> [0.7053319996471655, 0.34131818323294594, 0.4084836724883256, 0.20452172335941388, 0.5124065818560665, 0.4203474973940552, 0.6719502264788891, 0.7453268015406016, 0.09500886225101768, 0.9053707563920769]
# try this for your case
# 10.times {|i| @frames.push(Frame.new) }
# using array creation with block
# ty tadman for the advice
# @frames = Array.new(10) { Frame.new }
Array.new(10, Frame.new)
创建一个包含 10 个元素的数组,所有元素都指向一个 Frame
实例。要创建包含 10 个独立 Frame
实例的数组,您应该使用块形式。
Array.new(10) { Frame.new }
这将执行块 10 次并将每次执行的结果分配给共同发起索引。
An array can also be created by explicitly calling ::new
with zero,
one (the initial size of the Array
) or two arguments (the initial size
and a default object).
ary = Array.new #=> []
Array.new(3) #=> [nil, nil, nil]
Array.new(3, true) #=> [true, true, true]
Note that the second argument populates the array with references to
the same object. Therefore, it is only recommended in cases when you
need to instantiate arrays with natively immutable objects such as
Symbols, numbers, true or false.
To create an array with separate objects a block can be passed
instead. This method is safe to use with mutable objects such as
hashes, strings or other arrays:
Array.new(4) {Hash.new} #=> [{}, {}, {}, {}]
Array.new(4) {|i| i.to_s } #=> ["0", "1", "2", "3"]
Game
有一个包含十个 Frame
个实例的数组
class Frame
attr_accessor :rolls
def initialize
@rolls = ""
end
end
class Game
attr_accessor :frames
def initialize
@frames = Array.new(10, Frame.new)
end
def print_frames
@frames.each_with_index do |frame, idx|
p "Frame ##{idx+1}: #{frame.rolls}"
end
end
end
game = Game.new
rolls = [5, 5, 3, 7, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2]
curr = 0
rolls.each_with_index do |roll|
game.frames[curr].rolls << roll.to_s
if game.frames[curr].rolls.size == 2
curr += 1
end
end
p "Total rolls: #{rolls.size}"
p game.print_frames
我希望打印 10 行,每行都有一个 frame id 和一个由 2 个数字组成的字符串 但是,返回以下内容
"Total rolls: 20"
"Frame #1: 55374000000000000022"
"Frame #2: 55374000000000000022"
"Frame #3: 55374000000000000022"
"Frame #4: 55374000000000000022"
"Frame #5: 55374000000000000022"
"Frame #6: 55374000000000000022"
"Frame #7: 55374000000000000022"
"Frame #8: 55374000000000000022"
"Frame #9: 55374000000000000022"
"Frame #10: 55374000000000000022"
[#<Frame:0x0000565402e40528 @rolls="55374000000000000022">, #<Frame:0x0000565402e40528 @rolls="55374000000000000022">, #<Frame:0x0000565402e40528 @rolls="55374000000000000022">, #<Frame:0x0000565402e40528 @rolls="55374000000000000022">, #<Frame:0x0000565402e40528 @rolls="55374000000000000022">, #<Frame:0x0000565402e40528 @rolls="55374000000000000022">, #<Frame:0x0000565402e40528 @rolls="55374000000000000022">, #<Frame:0x0000565402e40528 @rolls="55374000000000000022">, #<Frame:0x0000565402e40528 @rolls="55374000000000000022">, #<Frame:0x0000565402e40528 @rolls="55374000000000000022">]
实例变量的作用类似于 class 帧之间共享的变量。所有 20 个卷数都连接在一起,而不是每个帧拥有一对。
代码有什么问题?是因为 Game
或 Frame
对象没有正确实例化吗?
方法 Array.new 定义为 new(size=0, default=nil) 这意味着第二个参数将是数组中所有对象的值,默认值。
这就是为什么对于您的情况,所有 10 个对象都是相同的。
https://ruby-doc.org/core-2.7.0/Array.html#method-c-new
这段代码可以帮助您解决
@frames = []
10.times {|i| @frames.push(rand) }
=> [0.7053319996471655, 0.34131818323294594, 0.4084836724883256, 0.20452172335941388, 0.5124065818560665, 0.4203474973940552, 0.6719502264788891, 0.7453268015406016, 0.09500886225101768, 0.9053707563920769]
# try this for your case
# 10.times {|i| @frames.push(Frame.new) }
# using array creation with block
# ty tadman for the advice
# @frames = Array.new(10) { Frame.new }
Array.new(10, Frame.new)
创建一个包含 10 个元素的数组,所有元素都指向一个 Frame
实例。要创建包含 10 个独立 Frame
实例的数组,您应该使用块形式。
Array.new(10) { Frame.new }
这将执行块 10 次并将每次执行的结果分配给共同发起索引。
An array can also be created by explicitly calling
::new
with zero, one (the initial size of theArray
) or two arguments (the initial size and a default object).ary = Array.new #=> [] Array.new(3) #=> [nil, nil, nil] Array.new(3, true) #=> [true, true, true]
Note that the second argument populates the array with references to the same object. Therefore, it is only recommended in cases when you need to instantiate arrays with natively immutable objects such as Symbols, numbers, true or false.
To create an array with separate objects a block can be passed instead. This method is safe to use with mutable objects such as hashes, strings or other arrays:
Array.new(4) {Hash.new} #=> [{}, {}, {}, {}] Array.new(4) {|i| i.to_s } #=> ["0", "1", "2", "3"]