Go - 修改解除引用的结构指针会更改大多数结构值,但不会更改切片

时间:2016-07-08 09:42:06

标签: pointers methods go slice chess

我试图创建一个结构板(棋盘)的浅表副本。在保存移动到电路板之前,我需要检查该移动是否可以控制移动器。

为此,在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,用于复制指针值的快捷方式。

2 个答案:

答案 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)

    // ...

请注意,您必须为所有引用类型执行类似的操作。