Wen

[Go言語] Sliceを完璧に複製するには? (How to perfectly clone a slice?)

N views

結論

b := append(a[:0:0], a...)

解説

a[:0:0]a[0:0:0] の省略で、 Full slice expressions(フルスライス式?)と言います。

  • その構文

    a[low : high : max]
    

    最初のインデックス(low) が 0の場合、a[: high : max] に省略することができます。

注意:普通のスライス式 a[0:0] ですと、 ba と同じメモリを使うことになります。

おまけ

b := make([]T, len(a))
copy(b, a)

OR

b := append([]T(nil), a...)

でも複製できますが、

前者は、nil slicenon-nil blank slice に、

後者は、non-nil blank slicenil slice に複製してしまう問題あります。

nil判定を入れれば問題解消できますが、コードが長くなります。

if a == nil {
    b = nil
} else {
    b = make([]T, len(a))
    copy(b, a)
}

ベンチマーク

テストコード

package main

import (
    "testing"
)

const N = 1024 * 1024
type T = int64
var xForMakeCopy = make([]T, N)
var xForAppend = make([]T, N)
var yForMakeCopy []T
var yForAppend []T

func Benchmark_MakeAndCopy(b *testing.B) {
    for i := 0; i < b.N; i++ {
        yForMakeCopy = make([]T, N)
        copy(yForMakeCopy, xForMakeCopy)
    }
}

func Benchmark_Append(b *testing.B) {
    for i := 0; i < b.N; i++ {
        yForAppend = append(xForAppend[:0:0], xForAppend...)
    }
}

テスト結果

❯ go version
go version go1.14.2 darwin/amd64
❯ go test -bench=.
goos: darwin
goarch: amd64
Benchmark_MakeAndCopy-8             1142            990016 ns/op
Benchmark_Append-8                  2289            526206 ns/op

appendcopy より2倍ぐらい早いようでした。

参考

How to efficiently clone a slice?

本記事は 「表示 - 非営利 - 改変禁止 4.0 国際 (CC BY-NC-ND 4.0)」 を採用。