2016-07-08 5 views
1

Я пытаюсь создать мелкую копию структуры Board (шахматная доска). Прежде чем сохранить переход на доску, мне нужно проверить, проверяет ли этот ход движок.Перейти - изменить разупорядоченный указатель структуры изменяет большинство значений структуры, но не срезов

Для этого в рамках метода Move (метод указателя), я разыменовать указатель, обновление и проверить этот возможной доски для проверки. Когда я изменяю значение одного значения типа Board (например, possible.headers = "Possible Varient"), исходная плата b не изменяется.

Но здесь, когда я вызываю метод 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, a []byte, всегда указывает на его исходное значение (даже если структура, которая содержит его, составляет разыменовывается. Ответ abhink использует Go func copy(dst, src []Type) int, https://golang.org/pkg/builtin/#copy, ярлык для копирования значений указателей.

+1

Является 'b.board' типа указателя (' board' является указателем на некоторый тип платы) ? Если это так, то мелкая копия 'possible: = * b' создает новую структуру' possible', которая имеет тот же адрес указателя в своем поле 'board' как' b.board'. Любой доступ/модификация, выполняемая путем ссылки на 'possible.board', изменит значение для' b', так как оба имеют один и тот же указатель. – abhink

+0

Нет, 'b.board' является' [] byte' – Nevermore

ответ

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) 

    // ... 

Обратите внимание, что вы должны сделать что-то подобное для всех ссылочных типов.

1

Выделение не делает копию. Он возвращает исходное значение, на которое указывает ваш указатель.

Вы получаете копию, потому что присваиваете это значение новой переменной. В 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 
    ... 
    } 
} 

Надежда, что помогает и мое объяснение не было запутанным :)

 Смежные вопросы

  • Нет связанных вопросов^_^