pointers - 非常令人困惑的变量变化

标签 pointers struct go race-condition

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/

相关文章:

c++ - 如何打印结构的每个成员

C:返回结构体指针的函数只能与 malloc 一起使用,为什么?

mysql - 在另一个函数中使用 sql 连接

c - C 中的段错误(核心转储)--简单指针

macos - Swift 中来自 CGImage 的 RGB 数据

delphi - ((指针)(P)+1)^什么时候可以起作用?

c++ - 使用前向声明编译时间 "null"?

c - 从 "gets(*buffer)"获取 Int 时遇到问题

rest - 如何使用证书 golang 发送 https 请求

go - 在 protobuf 文件中使用 google.protobuf.Value 并在结构中使用 go interface{} 字段,反之亦然