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

Dev*_*evK 3 go

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

具体来说,现在我建立一个游戏式炉排和我创建了一个CardStack类型,有一些方便的方法在卡片堆栈一个可以使用(读:玩家的手牌,弃牌堆...),例如DrawCards(...),AppendCards(...)...

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

这是我的CardStack:

type CardStack struct {
    cards []deck.Card
}
Run Code Online (Sandbox Code Playgroud)

这是我的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
}
Run Code Online (Sandbox Code Playgroud)

更多地解释 - 特别是在原始值的混乱中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} - ???
Run Code Online (Sandbox Code Playgroud)

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

任何形式的帮助表示赞赏.

编辑:

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

编辑2:

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

Jim*_*imB 5

在您的示例中,cardsin 的值DrawCards是切片的子CardsStack.cards切片,它引用同一后备数组中的值.

当您findCardCardStack.cards切片中调用并删除卡时,您正在操作cards参数所使用的相同数组.

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

ssCopy := make([]deck.Card, len(ss))
copy(ssCopy, ss)
cards.DrawCards(ssCopy)
Run Code Online (Sandbox Code Playgroud)

  • 是的,如果SubStack的意图是返回一个新的切片,那么你需要分配一个并复制该值(或者可能在SetCards中这样做.由你决定这里方法的具体语义) (2认同)