为什么不是put方法调用我的.to_s方法?
我认为定义一个自定义类的to_s
方法意味着调用该类的puts
方法将返回to_s
指定的输出。然而,在这个程序中,如果我写puts bingo_board.to_s
,我只会得到我渴望的结果。到底是怎么回事?为什么不是put方法调用我的.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"
它是因为你是从数组扩展。这就是为什么你会得到这种奇怪的行为。我没有看到你需要的扩展,所以只需删除它,事情就会按照你的预期工作。
如果你想知道为什么会发生这种情况,这里有一个更详细的答案。基本上,puts会为数组创建一个例外,因此当数组传递时,会在每个成员上调用puts。 Ruby Array#puts not using overridden implementation?
如果对象是一个Array
或可被转化为一个(即它实现to_ary
),然后puts
不会在对象上调用to_s
,而是迭代在物体和打印由内每个对象打电话给to_s
就可以了。
参见:
puts [1, 2]
# 1
# 2
[1, 2].to_s
# => '[1, 2]'
This is actually documented,虽然有点隐含:
如果调用数组参数,在一个新行写入每个元素。
正如@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
哇!这是一个快速解决方案。但是Array有自己的to_s方法。为什么我的自定义to_s方法无法覆盖它,@jwater? – pgblu 2014-10-19 17:21:21
tl;你离开我的链接的博士:数组的处理方式不同,没有人真正知道为什么。这是一个公平的总结吗? 另外:是否准确地说数组to_s方法不能被覆盖? – pgblu 2014-10-19 17:29:23
@pgblu - 不完全是,它被覆盖,如果你使用其他方法如say,print,它会调用你的to_s,但只要你使用puts方法,那么你是对的。 – jwater 2014-10-19 17:38:31