我认为为自定义类定义to_s
方法意味着在该类上调用puts
方法将返回to_s
指定的输出。但是,在这个程序中,如果我写puts bingo_board.to_s
,我只会得到我渴望得到的结果。发生了什么事?
class BingoBoard < Array
@@letters = %w[B I N G O]
def initialize
# populates an 5x5 array with numbers 1-100
# to make this accessible across your methods within this class, I made
# this an instance variable. @ = instance variable
@bingo_board = Array.new(5) {Array.new(5)}
@bingo_board.each_with_index do |column, i|
rangemin = 15 * i + 1
@bingo_board[i] = (rangemin..(rangemin+14)).to_a.sample(5)
end
@bingo_board[2][2] = "X" # the 'free space' in the middle
@game_over = false
end
def game_over?
@game_over
end
def generate_call
....
end
def compare_call(call)
@bingo_board[@@letters.index(call[0])].include? call[1]
end
def react_to_call(call)
...
end
def check_board
...
end
def show_column(num)
...
end
def to_s
result = ""
0.upto(4) do |val|
result += " " + @@letters[val] + " "
end
result += "\n\n"
0.upto(4) do |row|
0.upto(4) do |col|
val = @bingo_board[col][row]
result += " " if val.to_i < 10
result += val.to_s + " "
end
result += "\n"
end
result
end
end
my_board = BingoBoard.new
counter = 0
until my_board.game_over?
puts my_board.to_s # renders the board in accordance with my to_s method
call = my_board.generate_call
counter += 1
puts "\nThe call \# #{counter} is #{call[0]} #{call[1]}"
my_board.react_to_call(call)
gets.chomp
end
puts my_board # renders bubkes (i.e., nothing)
puts "\n\n"
puts "Game over"
答案 0 :(得分:2)
因为你从Array扩展了。这就是为什么你会得到奇怪的行为。我不知道你需要从哪里扩展,所以只需删除它就可以按照你的预期运行。
如果你想知道为什么会这样,那么这里有一个更详细的答案。基本上puts会使数组成为例外,因此当传递数组时会在每个成员上调用puts。 Ruby Array#puts not using overridden implementation?
答案 1 :(得分:2)
正如@jörgwmittag所说,这是一个特例。 IO#puts
方法处理数组 - 这意味着响应to_ary
的任何内容 - 以不同方式处理。它首先调用to_ary
然后遍历生成的数组的每个元素,并且只调用它们上的to_s
。它从不在数组本身上调用to_s
。
如果委托成员数组而不是从Array
进行子类化,则可以对“继承”(委派)的内容进行更精细的控制。然后,您可以从委派中排除to_ary
,这将阻止puts
将您的对象视为数组并触发此行为。
其他一般解决方案:
使用字符串插值或显式to_s
调用,以便puts
收到的内容已经是字符串:
puts "#{bingo_board}"
puts bingo_board.to_s
使用print
或printf
代替puts
:
print bingo_board,"\n"
printf "%s\n",bingo_board
答案 2 :(得分:1)
如果对象是Array
或者可以转换为一个(即它实现to_ary
),那么puts
将不会在对象上调用to_s
,而是迭代覆盖对象,并通过调用在中打印每个对象。
请参阅:
to_s
This is actually documented,虽然有些暗示:
如果使用数组参数调用,则将每个元素写入新行。
答案 3 :(得分:0)
看起来它运行Array#inspect
方法而不是您的自定义to_s
。在alias_method :inspect, :to_s
定义结束后添加to_s
将对您有所帮助。
但它只适用于p
,因为puts
运行each(&:inspect)
。