关于go:使用go切片应注意的一个小问题copy函数的重要性

起因是在写一个函数的时候

func (g *Grammar) extractCommonFactors() {
    flag := false
    newNonTerminalCounter := 0
    for i, production := range g.Productions {
        newAlternatives := []Alternative{}
        prefixMap := make(map[Symbol][]Alternative)
        for _, alternative := range production.Right {
            if len(alternative.Symbols) > 0 {
                firstSymbol := alternative.Symbols[0]
                if _, ok := prefixMap[firstSymbol]; !ok {
                    prefixMap[firstSymbol] = []Alternative{}
                }
                prefixMap[firstSymbol] = append(prefixMap[firstSymbol], alternative)
            }
        }
        for _, alternatives := range prefixMap {
            if len(alternatives) > 1 {
                flag = true
                commonPrefix := findLongestCommonPrefix(alternatives)
                newNonTerminalCounter++
                newValue := fmt.Sprintf("A%d", newNonTerminalCounter)
                newNonTerminal := Symbol{
                    Value:      newValue,
                    IsTerminal: false,
                }
                newRight := removeCommonPrefix(alternatives, commonPrefix)
                newProduction := Production{
                    Left:  newNonTerminal,
                    Right: newRight,
                }
                g.Productions = append(g.Productions, newProduction)
                var newAlternative Alternative
                newAlternative.Symbols = commonPrefix
                //bug呈现的中央
                newAlternative.Symbols = append(newAlternative.Symbols, newNonTerminal)
                newAlternatives = append(newAlternatives, newAlternative)
            } else {
                newAlternatives = append(newAlternatives, alternatives[0])
            }
        }
        g.Productions[i].Right = newAlternatives
    }
    if flag {
        fmt.Println("extractCommonFactors grammar:")
        for _, prod := range g.Productions {
            rightParts := make([]string, len(prod.Right))
            for i, alt := range prod.Right {
                symbols := make([]string, len(alt.Symbols))
                for j, sym := range alt.Symbols {
                    symbols[j] = sym.Value
                }
                rightParts[i] = strings.Join(symbols, "")
            }
            fmt.Printf("%s -> %s\n", prod.Left.Value, strings.Join(rightParts, "|"))
        }
    }
}

发现每次在执行

            newAlternative.Symbols = append(newAlternative.Symbols, newNonTerminal)                

时总会莫名其妙批改掉g.Productions 中的数据
起因就是因为

            var newAlternative Alternative
            newAlternative.Symbols = commonPrefix
            //bug呈现的中央
            newAlternative.Symbols = append(newAlternative.Symbols, newNonTerminal)

中的newAlternative.Symbols是一个数组切片,这里间接对切片赋值,实质上是将newAlternative.Symbols的内容批改为commonPrefix切片所指向的数组,所以后续在批改newAlternative.Symbols时对别的内容也会产生影响
改过为

var newAlternative Alternative
commonPrefixCopy := make([]Symbol, len(commonPrefix))
copy(commonPrefixCopy, commonPrefix)
newAlternative.Symbols = commonPrefixCopy
newAlternative.Symbols = append(newAlternative.Symbols, newNonTerminal)

之后问题就隐没了
因为copy函数是在内存中开拓一个新的数组给复制的切片应用,这样尽管耗费了更多的内存,但也更平安,是个更好的开发习惯

【腾讯云】轻量 2核2G4M,首年65元

阿里云限时活动-云数据库 RDS MySQL  1核2G配置 1.88/月 速抢

本文由乐趣区整理发布,转载请注明出处,谢谢。

您可能还喜欢...

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据