dpquu9206 2017-01-30 19:48 采纳率: 0%
浏览 79
已采纳

Golang-为什么此函数更改输入参数?

I'm learning Golang and I come from PHP background. I have a bit of trouble understanding some of the core functionalities at times.

Specifically, right now I'm building a Hearths game and I've created a CardStack type, that has some convenient methods one might use in a card stack (read: player's hand, discard pile...) such as DrawCards(...), AppendCards(...)...

The problem I have is that the function func (c* CardStack) DrawCards(cards []deck.Card) ([]deck.Card, error) {...} changes the argument cards []deck.Card and I cannot figure out why or how to avoid this.

This is my CardStack:

type CardStack struct {
    cards []deck.Card
}

This is my DrawCards method:

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
}

To explain a bit more - specifically the findCard(...) method that gets called in getCardsSlice messes with the original value (I've added comments to indicate where it happens).

If it's of any help, this is part of my main() method that I use for debugging:

// ...
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} - ???

What am I doing wrong and how should I go about doing this.

Any kind of help is appreciated.

Edit:

The whole CardStack file: http://pastebin.com/LmhryfGc

Edit2:

I was going to put it on github sooner or later (was hoping after the code looks semi-ok), here it is - https://github.com/d1am0nd/hearths-go/tree/cardstack/redo

  • 写回答

1条回答 默认 最新

  • drt41563 2017-01-30 20:10
    关注

    In your example, the value of cards in DrawCards is a sub-slice of the CardsStack.cards slice, which is referencing values in the same backing array.

    When you call findCard and remove a card from the CardStack.cards slice, you are manipulating the same array that the cards argument is using.

    When you want a copy of a slice, you need to allocate a new slice and copy each element. To do this in your example, you could:

    ssCopy := make([]deck.Card, len(ss))
    copy(ssCopy, ss)
    cards.DrawCards(ssCopy)
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥35 平滑拟合曲线该如何生成
  • ¥100 c语言,请帮蒟蒻写一个题的范例作参考
  • ¥15 名为“Product”的列已属于此 DataTable
  • ¥15 安卓adb backup备份应用数据失败
  • ¥15 eclipse运行项目时遇到的问题
  • ¥15 关于#c##的问题:最近需要用CAT工具Trados进行一些开发
  • ¥15 南大pa1 小游戏没有界面,并且报了如下错误,尝试过换显卡驱动,但是好像不行
  • ¥15 自己瞎改改,结果现在又运行不了了
  • ¥15 链式存储应该如何解决
  • ¥15 没有证书,nginx怎么反向代理到只能接受https的公网网站