起因是在写一个函数的时候
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 AlternativecommonPrefixCopy := make([]Symbol, len(commonPrefix))copy(commonPrefixCopy, commonPrefix)newAlternative.Symbols = commonPrefixCopynewAlternative.Symbols = append(newAlternative.Symbols, newNonTerminal)
之后问题就隐没了
因为copy函数是在内存中开拓一个新的数组给复制的切片应用,这样尽管耗费了更多的内存,但也更平安,是个更好的开发习惯