http://play.golang.org/p/Vd3meom5VF
我有一些 Go 中上下文无关语法的代码
我多次查看这段代码,但仍然没有看到任何需要更改结构值的原因。有人能明白为什么会发生如下变化吗?
规则:
S -> 。 [DP副总裁]
副总裁 -> 。 [V DP]
副总裁 -> 。 [V DP AdvP]
在我运行一些函数后,如行中
or2 = append(or2, OstarCF([]QRS{q}, []string{"sees"}, g2.Nullables(), g2.ChainsTo(g2.Nullables()))...)
不知怎的,我的结构值被改变了......我不知道为什么......
规则:
S -> 。 [副总裁]
副总裁 -> 。 [DP DP]
副总裁 -> 。 [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)
如你所见,我没有使用任何指针变量rule,它们只是用来实例化另一个结构体值,但是原始结构体字段rule怎么来的已经改变?函数 OstarCF 对此字段不执行任何操作 rule
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
}
最佳答案
由于使用了指针和 slice (也是引用),原始规则字段发生了变化。
在调用 OstarCF 之前,会调用 ChainsTo 方法。它按值使用语法对象,因此完成了复制,但规则字段是规则上的指针 slice 。所以当这个字段被复制的时候,它仍然指向原对象的数据。
然后,在方法 ChainsTo 中,Rules 字段上有一个循环。它复制 Right 字段,该字段是一个字符串 slice (因此它仍然指向原始对象的数据):
rhs := rule.Right
最后通过对rhs进行 slice 来声明一个ns变量:
ns := rhs[:i]
ns = append(ns, rhs[i+1:]...)
在此阶段,ns 变量仍然指向包含原始对象字符串 slice 的缓冲区。最初,i=0,因此 ns 是一个重用缓冲区的空 slice 。附加项目后,它们会替换原始数据。
这就是您的数据发生更改的原因。
您可以通过显式制作副本来解决此问题,例如将上面的行替换为:
ns := make( []string, 0, len(rhs) )
ns = append( ns, rhs[:i]...)
ns = append( ns, rhs[i+1:]...)
Go slice 已经取代了 C 指针算术,但在某些情况下它们几乎同样危险/具有误导性。
关于pointers - 非常令人困惑的变量变化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22110799/