Golang - 为什么这个函数会改变输入参数?

时间:2017-01-30 19:48:34

标签: go

我正在学习Golang,我来自PHP背景。我有时很难理解一些核心功能。

具体来说,现在我正在构建一个Hearths游戏并且我已经创建了一个CardStack类型,它有一些方便的方法可以在卡片堆栈中使用(读取:玩家的手,丢弃堆......),例如{ {1}},DrawCards(...) ...

问题我的问题是函数AppendCards(...)更改了参数func (c* CardStack) DrawCards(cards []deck.Card) ([]deck.Card, error) {...},我无法弄清楚为什么或如何避免这种情况。

这是我的CardStack:

cards []deck.Card

这是我的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()

我做错了什么,我应该怎么做呢。

感谢任何形式的帮助。

修改

整个CardStack文件:http://pastebin.com/LmhryfGc

EDIT2

我迟早要把它放在github上(希望代码看起来半好),这里是 - https://github.com/d1am0nd/hearths-go/tree/cardstack/redo

1 个答案:

答案 0 :(得分:5)

在您的示例中,cardsDrawCards的值是CardsStack.cards切片的子切片,它在同一支持数组中引用值。

当您致电findCard并从CardStack.cards切片中移除卡片时,您正在操作cards参数正在使用的相同数组。

如果需要切片的副本,则需要分配新切片并复制每个元素。要在您的示例中执行此操作,您可以:

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