2017-01-30 4 views
3

Я изучаю Голанг, и я родом из PHP. У меня есть немного проблем с пониманием некоторых основных функциональных возможностей.Golang - Почему эта функция меняет входной аргумент?

В частности, прямо сейчас я создаю игру Hearths, и я создал тип CardStack, который имеет некоторые удобные методы, которые можно использовать в стеке карт (читай: рука игрока, сбросить кучу ...), например DrawCards(...), AppendCards(...) ...

проблема у меня есть, что функция func (c* CardStack) DrawCards(cards []deck.Card) ([]deck.Card, error) {...} изменяет аргумент cards []deck.Card, и я не могу понять, почему и как избежать этого.

Это мой CardStack:

type CardStack struct { 
    cards []deck.Card 
} 

Это мой DrawCards метод:

func (c *CardStack) DrawCards(cards []deck.Card) ([]deck.Card, error) { 
    return c.getCardsSlice(cards, true) 
} 

// Returns cards that are missing 
func (c *CardStack) getCardsSlice(cards []deck.Card, rm bool) ([]deck.Card, error) { 
    var err error 
    var returnc = []deck.Card{} 
    for _, card := range cards { 
     fmt.Println("BEFORE c.findCard(cards): ") 
     deck.PrintCards(cards) // In my example this will print out {Kc, 8d}, which is what I expect it to be 
     _, err = c.findCard(card, rm) // AFTER THIS LINE THE cards VAR IS CHANGED 
     fmt.Println("AFTER c.findCard(cards): ") 
     deck.PrintCards(cards) // In my example this will print out {8d, 8d}, which is not at all what I expected 
     if err != nil { 
      return returnc, err 
     } 
    } 
    return returnc, nil 
} 

// Expects string like "Ts" or "2h" (1. face 2. suit) 
func (c *CardStack) findCard(cc deck.Card, rm bool) (deck.Card, error) { 
    for i, card := range c.GetCards() { 
     if cc == card { 
      return c.cardByIndex(i, rm) 
     } 
    } 
    return deck.Card{}, fmt.Errorf("Card not found") 
} 

func (c *CardStack) cardByIndex(n int, rm bool) (deck.Card, error) { 
    if n > len(c.GetCards()) { 
     return deck.Card{}, fmt.Errorf("Index out of bounds") 
    } 

    card := c.GetCards()[n] 
    if rm { 
     c.SetCards(append(c.GetCards()[:n], c.GetCards()[n+1:]...)) 
    } 
    return card, nil 
} 

Чтобы объяснить немного больше - в частности findCard(...) метод, который вызывается в getCardsSlice столовых с первоначальным значением (Я добавил комментарии, чтобы указать, где это происходит).

Если это какой-либо помощи, это часть моего main() метод, который я использую для отладки:

// ... 
ss, _ := cards.SubStack(1, 3) // ss now holds {Kc, 8d} 
ss.Print() // Prints {Kc, 8d} 
cards.Print() // Prints {5c, Kc, 8d} (assigned somewhere up in the code) 
cards.DrawCards(ss) // Draws {Kc, 8d} from {5c, Kc, 8d} 
cards.Print() // Prints {5c} - as expected 
ss.Print() // Prints {8d, 8d} - ??? 

Что я делаю неправильно и как я должен идти об этом.

Любые виды помощи приветствуются.

Edit:

Весь файл CardStack: http://pastebin.com/LmhryfGc

Edit2:

Я собирался поставить его на GitHub рано или поздно (надеялся после того, как код выглядит полу ОК), вот оно - https://github.com/d1am0nd/hearths-go/tree/cardstack/redo

+2

Мы не можем показать вам конкретную проблему с полным примером, но, похоже, вы проходите несколько кусочков, указывающих на один и тот же массив. Скорее всего, «GetCards» не делает то, что вы думаете. – JimB

+0

Я более чем счастлив обновить вас всем, что вам нужно. Дайте мне минутку, и я отредактирую свое оригинальное сообщение – devk

+0

@JimB Я создал Pastebin со своим стеком карт. 'GetCards' - это просто' return c.cards'. Если есть что-то еще, что вы думаете, может помочь мне сообщить – devk

ответ

5

В вашем примере значение cards в DrawCards - это суб-срез фрагмента CardsStack.cards, который ссылается на значения в одном массиве.

Когда вы вызываете findCard и удаляете карту из секции CardStack.cards, вы управляете тем же массивом, что и аргумент cards.

Если вам нужна копия фрагмента, вам нужно выделить новый срез и скопировать каждый элемент. Для этого в вашем примере вы можете:

ssCopy := make([]deck.Card, len(ss)) 
copy(ssCopy, ss) 
cards.DrawCards(ssCopy) 
+0

Спасибо большое! Итак, судя по тому, что мой метод '' SubStack' (https://github.com/d1am0nd/hearths-go/blob/cardstack/redo/hearths/cardstack.go#L120) меня надувает? Поскольку (если я правильно понимаю), он возвращает ссылку на тот же массив, а не создает копию. (также я положил его на github, так что теперь весь источник доступен) – devk

+2

Да, если намерение, если SubStack должно вернуть новый фрагмент, вам нужно выделить его и скопировать значение (или, возможно, сделать это в SetCards. до вас, чтобы определить конкретную семантику методов здесь) – JimB

+0

Отлично. Спасибо за помощь и простое объяснение! – devk

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