我正在尝试创建 struct Board(棋盘)的浅拷贝。在将移动保存到棋盘之前,我需要检查该移动是否使移动器处于检查状态。
为此,在 Move 方法(指针方法)中,我取消引用指针,更新并检查这个可能板检查。当我更改 Board 类型的单个值(例如 possible.headers = "Possible Varient"
)的值时,原始 b
Board 不会更改。
但是在这里,当我调用方法 updateBoard() 时,它会更新两个板。我仍然收到错误(无法进入检查),但主线程认为 b.board
(棋盘位置)已更改。
func (b *Board) Move(orig, dest int) error {
// validation
...
// Update
possible := *b // A 'shallow copy'?
possible.updateBoard(orig, dest, val, isEmpassant, isCastle)
king := possible.findKingPositionOfThePlayerWhoMoved()
isCheck := possible.isInCheck(king) // bool takes the king to check for
if isCheck {
return errors.New("Cannot move into Check")
}
b.updateBoard(orig, dest, val, empassant, isCastle)
return nil
奇怪的是,并非所有由 updateBoard()
更新的值都会改变。所以 b.toMove
值不会改变,但 b.board
值会改变(棋子的位置)。这意味着如果我改为传递 possible := b
,游戏将永远是白棋(toMove 在 updateBoard() 方法中交替)。使用 possible := *b
,轮流交替工作,直到有人进入检查状态。然后移动应用于 b.board
,但错误被抛回并且它仍然是检查玩家轮到(意味着 possible.updateBoard()
没有更新 b .toMove.
编辑
正如 abhink 指出的那样,在 Go Slices usage and internals 中,
Slicing does not copy the slice's data. It creates a new slice value that points to the original array.
b.board
,一个 []byte
,始终指向其原始值(即使保存它的结构被取消引用。 abhink 的回答使用了 Go func copy(dst, src []Type) int
, https://golang.org/pkg/builtin/#copy,这是一种复制指针值的快捷方式。
最佳答案
因为 b.board
是一个 slice 类型,它是一个引用类型 ( https://blog.golang.org/go-slices-usage-and-internals ) 并且表现得像一个指针。因此,对 possible.board
所做的任何更改都将显示在 b
中。您可以尝试制作 b.board
的副本,如下所示:
func (b *Board) Move(orig, dest int) error {
// validation
...
// Update
possible := *b // A 'shallow copy'?
boardCopy := make([]byte, len(b.board))
copy(boardCopy, b.board)
possible.board = boardCopy
possible.updateBoard(orig, dest, val, isEmpassant, isCastle)
// ...
请注意,您必须对所有引用类型执行类似的操作。
关于pointers - 修改取消引用的结构指针会更改大多数结构值,但不会更改 slice ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38263511/