2016-08-13 3 views
5

Golangのappend()で奇妙な動作が発生しました。スライスの容量が新しい基本的な配列が割り当てられるかどうかについての基本的な考え方を理解しますが、追加がappendの結果に影響を与えた後にfmt.Println()を使用したかどうかはどうしてですか?ここでコードを実行するためのGolang append()で異常な動作がfmt.Println()の影響を受けています

package main 

import "fmt" 

func main() { 
    a := []byte("AAA") 

    b := append(a, []byte("BBB")...) 
    fmt.Println(" a: ", string(a), " b: ", string(b)) 

    c := append(a, []byte("CCC")...) 
    fmt.Println(" a: ", string(a), " b: ", string(b), " c: ", string(c)) 

    fmt.Println(&b) //try commenting this out and in and running the program 
} 

リンク:https://play.golang.org/p/jJ-5ZxTBIn

+1

OP、私は無駄な最初の割り当てを取り除くことで例を簡略化しました。あなたが反対するなら元に戻すことができます。 –

+2

これは実際にはコンパイラが間違って何かを最適化できると誤って思っていて、後で印刷されるときにbの正しい値しか保持しないように見えます。私は、これが例えば1.4.2では起こらないことを確認しました。これは、既に満たされているバグがない場合に、ゴランナットの注意を引くべきです。 –

+0

私は、この例はあなたに多くのことを混乱させる可能性があることを理解します。素晴らしい記事はhttps://blog.golang.org/go-slices-usage-and-internalsです。スライスは何か、それはアレイを指します - それは、どこにポイント、彼の長さと容量を覚えています。通常、容量については気にしませんが、追加では非常に重要です。十分なスペースがあればAppendは前のものとメモリを共有するかもしれませんが、そうでなければ共有しません。私たちの場合は、a = []バイトの後に* fmt.Println(cap(a))*を入れてください。それは私に8を返しました。つまり、bとcは短くなりますが、同じメモリを指し示すことになります。 – lofcek

答えて

3

あなたがおっしゃるとおり The Go Playgroundバージョンは(go1.6.2)古いためで、新しいバージョンを使用します。


go version go1.7rc6を使用して)正しい出力は次のとおり

a: AAA b: AAABBB 
a: AAA b: AAACCC c: AAACCC 

1-移動遊び場(go1.6.2):

package main 

import "fmt" 

func main() { 
    a := make([]byte, 100, 1000) 
    a = []byte("AAA") 

    b := append(a, []byte("BBB")...) 
    fmt.Println(" a: ", string(a), " b: ", string(b)) 

    c := append(a, []byte("CCC")...) 
    fmt.Println(" a: ", string(a), " b: ", string(b), " c: ", string(c)) 

    //fmt.Println(&b) //try commenting this out and in and running the program 
} 

出力:

a: AAA b: AAABBB 
a: AAA b: AAABBB c: AAACCC 

2-移動遊び場(go1.6.2):

package main 

import "fmt" 

func main() { 
    a := make([]byte, 100, 1000) 
    a = []byte("AAA") 

    b := append(a, []byte("BBB")...) 
    fmt.Println(" a: ", string(a), " b: ", string(b)) 

    c := append(a, []byte("CCC")...) 
    fmt.Println(" a: ", string(a), " b: ", string(b), " c: ", string(c)) 

    fmt.Println(&b) //try commenting this out and in and running the program 
} 

出力:go version go1.7rc6を用い

a: AAA b: AAABBB 
a: AAA b: AAACCC c: AAACCC 
&[65 65 65 67 67 67] 

package main 

import "fmt" 

func main() { 
    a := make([]byte, 100, 1000) 
    a = []byte("AAA") 

    b := append(a, []byte("BBB")...) 
    fmt.Println(" a: ", string(a), " b: ", string(b)) 

    c := append(a, []byte("CCC")...) 
    fmt.Println(" a: ", string(a), " b: ", string(b), " c: ", string(c)) 

    //fmt.Println(&b) //try commenting this out and in and running the program 
} 

O utput:

a: AAA b: AAABBB 
a: AAA b: AAACCC c: AAACCC 
+0

一定! – Salitter

1

私が要約します:

a := make([]byte, 100, 1000) 
a = []byte("AAA") 

は、最初の行では、スライスを作成しますが、第二に、それは再び新しい配列とスライスを作成します。

この新しい配列の容量は、コンパイラのバージョンによって異なります。そのため、書かれたコードは、3以上であることを前提にしてはなりません。

追加を使用する場合は注意してください。返されたスライスは、前のスライスの浅いか深いコピーである可能性があります。どちらがアレイ容量に依存するか。ディープコピーが必要な場合は、手動で行う必要があります。

b:=make([]byte, len(a)) 
copy(b,a) 
+0

これは全く質問に答えません。問題はコンパイラのバグでした。 –

関連する問題