我正在写一个简单的Tic Tac Toe游戏,其中我有一个用于棋盘,玩家,计算机和游戏本身的课程.在我的Board类中,我将类变量@board(它是一个数组)设置为attr_reader,它应该禁止直接写入它.虽然以下方法不起作用(按预期)
game_board = Board.new
game_board.board = "some junk"
Run Code Online (Sandbox Code Playgroud)
以下工作,我不想发生
game_board = Board.new
game_board.board[0] = "some junk"
Run Code Online (Sandbox Code Playgroud)
如何停止将类数组变量@board写入?目前的类代码如下:
class Board
attr_reader :board
def initialize
create_board
end
private
def create_board
@board = Array.new(3).map{Array.new(3)}
end
end
game_board = Board.new
game_board.board
#=> [[nil,nil,nil],[nil,nil,nil],[nil,nil,nil]]
game_board.board = "junk"
#=> undefined method 'board ='
game_board.board[0] = "junk"
game_board.board
#=> ["junk",[nil,nil,nil],[nil,nil,nil]] #I don't want to allow this!
Run Code Online (Sandbox Code Playgroud)
我试过谷歌搜索,但无济于事,但我是一个完整的初学者,所以我可能没有使用正确的搜索条件
我相信你需要使数组不可变.
您可以使用Array#freeze来实现这一目标.
之后您的代码应如下所示:
class Board
attr_reader :board
def initialize
create_board
end
private
def create_board
@board = Array.new(3).map{Array.new(3).freeze}.freeze
end
end
Run Code Online (Sandbox Code Playgroud)
在运行第一个示例时:
>> game_board = Board.new
#<Board:0x00000001648b50 @board=[[nil, nil, nil], [nil, nil, nil], [nil, nil, nil]]>
>> game_board.board = "some junk"
NoMethodError: undefined method `board=' for #<Board:0x00000001648b50>
from (irb):14
from /home/alfie/.rvm/rubies/ruby-2.1.3/bin/irb:11:in `<main>'
Run Code Online (Sandbox Code Playgroud)
在运行第二个示例时:
>> game_board = Board.new
#<Board:0x00000001639e48 @board=[[nil, nil, nil], [nil, nil, nil], [nil, nil, nil]]>
>> game_board.board[0] = "some junk"
RuntimeError: can't modify frozen Array
from (irb):16
from /home/alfie/.rvm/rubies/ruby-2.1.3/bin/irb:11:in `<main>'
Run Code Online (Sandbox Code Playgroud)
attr_reader
仅定义,不会attr_writer
,仅阻止对@board
变量的赋值.换句话说,您的Board
类不公开接口来修改存储的内容@board
,但不会阻止修改初始值.
你可以使用freeze
:
def create_board
@board = Array.new(3) { Array.new(3).freeze }
@board.freeze
end
Run Code Online (Sandbox Code Playgroud)
(另外,你不需要map
那里)
冻结顶级数组和嵌套数组将完成您描述的操作,但我想它也会破坏您的游戏,因为完全不可能进行修改.
我建议的是不要暴露@board
并将其视为私有.然后,您应该公开一个接口来设置电路板中的值,并提供一种方法来返回电路板的只读表示.
class Board
def initialize
create_board
end
def []=(x, y, value)
@board[x][y] = value
end
def board
@board.map { |a| a.dup.freeze }.freeze
end
private
def create_board
@board = Array.new(3) { Array.new(3) }
end
end
b = Board.new
b.board
# => [[nil, nil, nil], [nil, nil, nil], [nil, nil, nil]]
b[1,2] = "x"
b[0,0] = "o"
b.board
# => [["o", nil, nil], [nil, nil, "x"], [nil, nil, nil]]
b.board[0] = "junk"
# RuntimeError: can't modify frozen Array
b.board[0][1] = "junk"
# RuntimeError: can't modify frozen Array
b.board
# => [["o", nil, nil], [nil, nil, "x"], [nil, nil, nil]]
Run Code Online (Sandbox Code Playgroud)