我试图创建一个结构板(棋盘)的浅表副本。在保存移动到电路板之前,我需要检查该移动是否可以控制移动器。
为此,在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,
切片不会复制切片的数据。它创建一个指向原始数组的新切片值。
b.board
,[]byte
,始终指向其原始值(即使持有它的结构取消引用。abhink的答案使用Go { {1}},https://golang.org/pkg/builtin/#copy,用于复制指针值的快捷方式。
答案 0 :(得分:2)
取消引用不会复制。它返回指针指向的原始值。
您获得一份副本,因为您要将该值分配给新变量。在go中,每个赋值都会像每次传递给函数一样复制。如果您指定或传递引用,则会复制该引用。
在您的情况下,您复制值b指向的值。在该结构中,存在类似于b.board切片的指针(切片具有指向底层数组的指针)。所以去创建切片的副本。副本仍指向与原始b变量中的切片相同的数组。如果更改该阵列,则会更改两个板。
您需要为Board结构实现一个复制功能,该功能正确地创建处理每个变量的结构的副本,具体取决于它的类型并返回新的板。
类似的东西:
func (b *Board) copy() *Board {
boardCopy := make([]byte, len(b.board))
copy(boardCopy, b.board)
return &Board{
moveTo: b.moveTo,
board: boardCopy
...
}
}
希望有帮助,我的解释并不令人困惑:)
答案 1 :(得分:1)
由于b.board
是切片类型,因此它是引用类型(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)
// ...
请注意,您必须为所有引用类型执行类似的操作。