[Go] Slices

Slices

Go 에서는 Array 보다는 Slice 더 자주 사용한다. 이유는 Slice의 유연함 때문이다.
슬라이스는 배열과 비슷하지만 길이가 가변적이다.

Slice의 특징

Slice Internals

슬라이스 내부의 모습을 살펴보자.
슬라이스를 구성하는 요소는 세가지가 있다.
slice internals

  1. ptr | Pointer 포인터
    슬라이스의 포인터는 배열의 첫 번재 요소를 가리킨다.
  2. len Length 길이
  3. cap Capacity 용량

용량과 길이가 구분되어 있는 이유는?

Slice expressions

Syntax

Slice에 값 추가

append() 함수는 슬라이스 동작 원리를 이해하는데 매우 중요하다.

append() 함수를 통해 슬라이스의 끝에 값을 추가할 수 있다.

cc := []int{1, 2, 3}
cc = append(cc, 7, 0, 88)
fmt.Println(cc) // [1 2 3 7 0 88]

Slice + Slice

slice 에 다른 slice를 append 시킬 때는 ...를 사용한다.

Syntax
slice1 = append(slice1, slice2...)

d := []int{10, 100, 1000}
e := []int{11, 111, 1111}
d = append(d, e...) // 슬라이스 d에 e를 추가
fmt.Println(d) // Slice d :  [10 100 1000 11 111 1111]

Reference Type

슬라이스는 레퍼런스 타입이다.
슬라이스는 내장된 배열에 대한 Pointer이다.
sliceA에 또 다른 슬라이스인 sliceB를 대입한다면 값이 복사되는 것이 아니라 참조가 된다.

// Reference Type
sliceA := []int{1, 2, 3}
var sliceB []int
sliceB = sliceA // sliceB 에 sliceA 대입
sliceB[0] = 100000 // sliceB의 첫 번째 요소 변경
fmt.Println(sliceA) // [100000 2 3]
fmt.Println(sliceB) // [100000 2 3]

Slice and copy function

슬라이스의 요소를 모두 복사하고자 한다면 copy() 함수를 사용한다.

Syntax
copy(\, \)</code>

  // Copy one slice into another slice
  s1 := []int{1, 2, 3, 4, 5}
  s2 := make([]int, 5) // make 함수로 공간을 할당
  copy(s2, s1)

  fmt.Println(s1) // [1 2 3 4 5]
  fmt.Println(s2) // [1 2 3 4 5]

복사를 완료하였으니 복사된 슬라이스(s2)의 요소를 변경한 후 원본 슬라이스(s1)에 영향을 미치는지 살펴보도록 하자.

  // Slice modification
  s2[0] = 1001010
  fmt.Println("Original s1 : ", s1) //  [1 2 3 4 5]
  fmt.Println("Coppeid s2 : ", s2)  // [1001010 2 3]

복사한 s2의 첫 번째 요소만 변경되었고, 원본 슬라이스는 영향을 받지 않았다.

fmt.Println(s1) // [1 2 3 4 5] fmt.Println(s2) // [1 2 3]



### Sub-slice  
슬라이스의 일부를 떼어 부분 슬라이스를 만들 수 있다.  
**Syntax**  
<code>\<subSlice> := \<originalSlice>[start_index:end_index]</code>

end index는 인덱스보다 1 많다.
  * end index == Total index + 1
    * 만약 길이가 7인 index의 슬라이스의 끝까지 참조하고자 한다면 <code>[0:7]</code> 이 아닌 <code>[0:8]</code> 이 되어야 한다.
  * 참조이기 때문에 부분 슬라이스의 요소를 바꾸면 배열의 요소도 바뀐다.

  ```go
  s := []int{1, 2, 3, 4, 5, 6, 7, 8}
	subS := s[2:5]
	fmt.Println(subS) // [3 4 5]
  subAll := s[0:8]
	fmt.Println(subAll) // [1 2 3 4 5 6 7 8]
  subEnd := s[0:len(s)]
  fmt.Println(subEnd) // [1 2 3 4 5 6 7 8]
  ss := []string{"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"}
	fmt.Println(ss[1:2]) // [Tue]
	fmt.Println(ss[1:1]) // []
	fmt.Println(ss[3:5]) // [Thu Fri]
  fmt.Println(ss[:])   // [Mon Tue Wed Thu Fri Sat Sun]
	fmt.Println(ss[:2]) // [Mon Tue]
	fmt.Println(ss[1:]) // [Tue Wed Thu Fri Sat Sun]

Reverse Slice

Reverse Slice의 구현

func reverse(s []int) {
  for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
      s[i], s[j] = s[j], s[i]
  }
}