非常混乱的变量

时间:2014-03-01 05:58:44

标签: pointers struct go race-condition

http://play.golang.org/p/Vd3meom5VF

我在Go

中有一些上下文无关语法的代码

我正在看这段代码很多次,但仍然没有看到任何改变struct值的原因。有人能看出为什么会发生以下变化吗?

规则:
S - > 。 [DP VP]
VP - > 。 [V DP]
VP - > 。 [V DP AdvP]

我在行中运行了一些函数

 or2 = append(or2, OstarCF([]QRS{q}, []string{"sees"}, g2.Nullables(), g2.ChainsTo(g2.Nullables()))...)

不知怎的,我的结构值发生了变化......我不知道为什么......

规则:
S - > 。 [VP VP]
VP - > 。 [DP DP]
VP - > 。 [AdvP AdvP AdvP]

这应与上述相同。

 Rules:
 S -> DP,VP
 VP -> V,DP
 VP -> V,DP,AdvP

 or2 := []QRS{}
 g2 := ToGrammar(cfg2)
 fmt.Printf("%s\n", g2)

 for _, rule := range g2.Rules {
        q := QRS{
            one:   rule.Src,
            two:   []string{},
            three: rule.Right,
        }
        or2 = append(or2, OstarCF([]QRS{q}, []string{"sees"}, g2.Nullables(), g2.ChainsTo(g2.Nullables()))...)
    }

    fmt.Printf("%s\n", g2)

如您所见,我没有使用任何指针变量规则,它们仅用于实例化另一个结构值,但原始结构字段规则如何已经改变?函数OstarCF对此字段规则

没有任何作用
 func OstarCF(Qs []QRS, R []string, nD map[string]bool, cD map[string][]string) []QRS {
    symbols := []string{}
    for _, r := range R {
        symbols = append(symbols, cD[r]...)
    }
    product := []QRS{}
    for _, Q := range Qs {
        a := Q.one
        b := Q.two
        c := Q.three
        if len(c) > 0 && CheckStr(c[0], symbols) {
            b = append(b, c[0])
            np := QRS{
                one:   a,
                two:   b,
                three: c[1:],
            }
            product = append(product, np)

            for len(np.three) > 0 && nD[np.three[0]] == true {
                np.two = append(np.two, np.three[0])
                np = QRS{
                    one:   np.one,
                    two:   np.two,
                    three: np.three[1:],
                }
                product = append(product, np)
            }
        }
    }
    return product
 }

1 个答案:

答案 0 :(得分:2)

原始规则字段更改,因为使用了指针和切片(也是引用)。

在调用OstarCF之前,调用ChainsTo方法。它按值使用语法对象,因此复制完成,但规则字段是规则上的一个指针片。因此,当复制此字段时,它仍然指向原始对象的数据。

然后,在方法ChainsTo中,Rules字段上有一个循环。它复制了Right字段,它是一个字符串片段(因此它仍然指向原始对象的数据):

rhs := rule.Right

最后,通过切片rhs:

声明一个ns变量
ns := rhs[:i]
ns = append(ns, rhs[i+1:]...)

在此阶段,ns变量仍指向包含原始对象的字符串切片的缓冲区。最初,i = 0,因此ns是重用缓冲区的空切片。附加项目后,它们将替换原始数据。

这就是您的数据发生变化的原因。

您可以通过显式制作副本来解决此问题,例如将上述行替换为:

ns := make( []string, 0, len(rhs) )
ns = append( ns, rhs[:i]...)
ns = append( ns, rhs[i+1:]...)

Go切片已经取代了C指针算法,但在某些情况下它们几乎可以像危险/误导一样。