代码之家  ›  专栏  ›  技术社区  ›  user2671513

非常令人困惑的变量变化

  •  2
  • user2671513  · 技术社区  · 11 年前

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

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

    我看了很多遍这段代码,仍然看不到任何改变结构值的原因。有人知道为什么会发生这样的变化吗?

    规则:
    S->。[DP VP]
    副总裁->。[V压差]
    副总裁->。[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)
    

    如您所见,我没有使用任何指针作为变量 规则 ,并且它们仅用于实例化另一个结构值,但原始结构字段是怎么来的 规则 改变了吗?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 回复  |  直到 11 年前
        1
  •  2
  •   Didier Spezia    11 年前

    由于使用了指针和切片(也是引用),原始规则字段发生了更改。

    在调用OstarCF之前,将调用ChainsTo方法。它按值使用语法对象,因此进行了复制,但Rules字段是Rules上的一部分指针。因此,当复制此字段时,它仍然指向原始对象的数据。

    然后,在方法ChainsTo中,规则字段上有一个循环。它复制了作为字符串片段的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指针算法,但在某些情况下,它们几乎同样危险/误导。