[Go]配列とスライス

22548 ワード

アレイとスライス

  • Sliceは、javaのArrayListに類似する配列ベースのより柔軟なデータ構造である.
  • Goは主に配列ではなくシートを使用する
  • arr1 := [...]int{1, 2, 3}	// 배열
    arr2 := [3]int{1, 2, 3}		// 배열
    slice1 := []int{1, 2, 3}		// 슬라이스
    slice2 := make([]int, len(arr1))	// 슬라이스

    整列


    There are major differences between the ways arrays work in Go and C. In Go,
  • Arrays are values. Assigning one array to another copies all the elements.
  • In particular, if you pass an array to a function, it will receive a copy of the array, not a pointer to it.
  • The size of an array is part of its type. The types [10]int and [20]int are distinct.
  • スライス

  • Sliceは、배열 포인터길이용량の3つのフィールドからなる構造体である.
  • スライスはcapのサイズのアレイであり、アレイが複製のために移動すると、スライスは別のアレイを指します.
  • if you assign one slice to another, both refer to the same array.
  • append

    nums := make([]int, 3, 5)
    nums = append(nums, 1)
  • 容量を超えていない場合は、値を追加し、長さを増やして再割り当てします.
  • 容量を超えると、値を入力して戻し、スライスを再割り当てするためのより大きな配列が作成されます.
  • copy

    src := []int{1, 2, 3}
    dst := src
  • dstは、srcSlice自体のアドレス値のみをコピーします.
  • src変更されると、dstも変更されます.
  • src := []int{1, 2, 3}
    if n := copy(dest, src); n != len(src) {
        fmt.Println("복사가 덜 됐습니다.")
    }
  • len(src)およびlen(dst)は、小さい値のみをコピーします.
  • スライスを完全にコピーするには、次の操作を実行する必要があります
  • // 1번
    src := []int{1, 2, 3}
    dst := make([]int, len(src))
    copy(dst, src)
    // 2번
    src := []int{1, 2, 3}
    var dst []int
    dst := append(dst, src...)

    insert

    func Example_sliceInsert1() {
    	a := []int{0, 1, 2, 3, 4}
    	var res []int
    	n := 2
    	if n <= len(a) {
    		res = append(a[:n+1], a[n:]...)
    		res[n] = 100
    	} else {
    		res = append(a, 100)
    	}
    	fmt.Println(res)
    
    	// Output:
    	// [0 1 100 2 3 4]
    }
    
    func Example_sliceInsert2() {
    	a := []int{0, 1, 2, 3, 4}
    	n := 2
    
    	a = append(a, 1)
    	copy(a[n+1:], a[n:])
    	a[n] = 100
    
    	fmt.Println(a)
    
    	// Output:
    	// [0 1 100 2 3 4]
    }

    delete


    順序が変更できない場合、O(N)

    func Example_sliceDelete1() {
    	a := []int{0, 1, 2, 3, 4}
    	n := 2
    	a = append(a[:n], a[n+1:]...)
    	fmt.Println(a)
    
    	// Output:
    	// [0 1 3 4]
    }
    
    func Example_sliceDelete2() {
    	a := []int{0, 1, 2, 3, 4}
    	n := 2
    	k := 2	// 연속된 k개의 원소 삭제
    	a = append(a[:n], a[n+k:]...)
    	fmt.Println(a)
    
    	// Output:
    	// [0 1 4]
    }

    シーケンス可変時O(1)

    func Example_sliceDelete3() {
    	a := []int{0, 1, 2, 3, 4}
    	n := 2
    	a[n] = a[len(a)-1]
    	a = a[:len(a)-1]
    	fmt.Println(a)
    
    	// Output:
    	// [0 1 4 3]
    }
    
    func Example_sliceDelete4() {	// 이 경우 O(N)
    	a := []int{0, 1, 2, 3, 4}
    	n := 1
    	k := 4
    	split := len(a)-k
    	if n+k > split {
    		split = n+k
    	}
    	copy(a[n:n+k], a[split:])
    	a = a[:len(a)-k]
    	fmt.Println(a)
    
    	// Output:
    	// [0]
    }

    削除時のメモリリーク


    削除したターゲットシートの内部にポインタがある場合、メモリリークが発生します.
    スライスをカットしても、使用するアレイ(メモリ)は元のままで、GCターゲットにありません.このとき,配列要素がポインタであれば,そのポインタが指すオブジェクトも有効と考えられ,メモリ空間を占有しGCを行わないため,漏水が発生する.
    したがって、nilを使用して消去する必要があります.
    copy(a[i:], a[i+k:])
    for i := 0; i < k; i++ {
        a[len(a)-1-i] = nil
    }
    a = a[:len(a)-k]