본문으로 바로가기
728x90
반응형
728x170

Slice가 왜 Slice인지 알아 보도록 해봅시다.

Slice는 어떤 일부를 잘라내서 덜어내는걸 말하는데 Golang의 Slice는 일부를 잘라낼 수가 있습니다.

 

그럼 어떻게 하는지 살펴보죠.

a [10]int

10개짜리 배열이 있다 가정하고 []를 이용해서 배열의 요소를 접근하는데

a [10]int
a[3]

이렇게 하면 a의 4번째 배열요소를 가져올 것이다. 그래서 a가 1~10까지 10개의 요소를 가지고 있다고 하면

a[3] == 4 가 될 것 입니다.

Slice도 마찬가지 입니다.

a []int
a[4:7]

Slice는 []안에 ':'을 붙여서 숫자 2개를 적습니다.

이 뜻은 첫번째 부분은 시작 index이고 두번째 부분은 마지막Index 부분인데 5~6번째까지 가져옵니다.

a[StartIndex : EndIndex]

Start부터 해서 End까지 하는데 End는 포함되지 않습니다.

그래서 만약에

a[0:9]

라고 한다면 0 ~ 8번째까지 입니다.

또 하나 예를 들어

  a:= []int {1,2,3,4,5,6,7,8,9,10}
  a[4:8]

을 하게 되면 [5,6,7,8]을 가져 옵니다.

 

이것을 코드로 진행해보죠.

  package main

  import "fmt"

  func main() {
    a := []int {1,2,3,4,5,6,7,8,9,10}
    b := a[4:8]

    fmt.Println(b)
  }

a는 1 ~ 10까지 가지고 있는 배열이고, b는 a의 슬라이스인데 5~7번째까지 값을 가져오는 슬라이스 입니다.

그래서 b의 요소를 출력해보면

[5, 6, 7, 8]이 나오는 것을 확인 할 수 있습니다.


배열은 0부터 시작하기 때문에 다음과 같이 나오는 것을 알 수 있습니다.

 a := []int {1,2,3,4,5,6,7,8,9,10}
             0 1 2 3 4 5 6 7 8 9

조금 더 보자면 시작 인덱스를 끝나는 인덱스를 적지 않으면 끝까지 슬라이스 하게 됩니다.

   package main

  import "fmt"

  func main() {
    a := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
    b := a[4:8]
    c := a[4:]
    fmt.Println(b)
    fmt.Println(c)
  }

아까와 같은 상황에서 C만 추가하여 출력시켰다. 5번째 값부터 가져 올 것 입니다.

반대로 a[:4]를 하게 되면 처음부터 4번째까지 나오게 됩니다.

  package main

  import "fmt"

  func main() {
    a := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
    b := a[4:8]
    c := a[4:]
    d := a[:4]
    fmt.Println(b)
    fmt.Println(c)
    fmt.Println(d)
  }

처음부터 4번째까지 Slice되는 것을 확인할 수 있습니다.

 

그러면 Slice가 어떻게 동작하는지 보자! Slice는 이름 그대로 잘라내는것은 아닙니다.

  a := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
  b := a[4:8]

이렇게 있을 때 a배열에 5~8까지만 가리키고 있는 것이라고 보면 됩니다.

지난번에 원래 원 배열이 있고, 그것을 가리키는 포인터라고 했었는데 a는 시작 위치를 가리키고 있는 거라고 한다면 b는 a배열의 5번째부터 가리키고 있는 것이고, 이 때 b의 길이는 4입니다.

그러니까 a의 일부분을 가리키고 있다고 보면 됩니다.

 

이걸 어떻게 확인해볼 수 있냐면

  a := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
  b := a[4:8]

이 코드에서 5,6,7,8을 가리키고 있다고 했는데 이 때 b의 첫번째와 두번째를 바꾸고 a를 찍어줍니다.

그러면 어떻게 될까요?

원래 a는 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]이였는데 [1, 2, 3, 4, 1, 2, 7, 8, 9, 10]으로 중간값이 바뀐 것을 알 수 있습니다.
b는 잘라낸게 아니라 a의 5번째부분을 가리키고 있기 때문에 b의 첫번째는 5가 되며 같은 메모리를 쓰고 있기 때문에 a의 슬라이스가 바뀌는 것이죠.

그래서 슬라이스는 말 그대로 잘라오는게 아니라 그 일부분을 가리킨 슬라이스를 새로 만든 것이고, 같은 메모리를 가리키고 있다는 것을 주의하고 알고 있어야 합니다.

 

몇가지 슬라이스를 활용한 예제들을 살펴보죠!

배열이 아래와 같이 있을 때 배열의 맨끝을 하나씩 삭제하려고 합니다. 어떻게 해야할까요?

a := []int {1,2,3, .... 10}

처음에 10을 없애고, 9를 없애고, 8을 없애는 식으로 하나씩 지워나가는 것을 만들어보죠.

  package main

  import "fmt"

  func RemoveBack(a []int) []int {
    return a[:len(a)-1]
  }

  func main() {
    a := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

    for i := 0; i < 5; i++ {
        a = RemoveBack(a)
    }

    fmt.Println(a)

  }

하나씩 지워가는 RemoveBack()이라는 함수를 만든다고 하자. 이 함수의 입력값은 슬라이스를 받고, 출력은 슬라이로 나가도록 합니다.

그랬을 때 a가 for문을 도는데 5번을 돈다고 가정하고,  a를 출력하도록 만들어보죠.

 

그러면 어떻게 Back을 해야 할까요?

  package main

  import "fmt"

  func RemoveBack(a []int) []int {
    return a[:len(a)-1]
  }

  func main() {
    a := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

    for i := 0; i < 5; i++ {
        a = RemoveBack(a)
    }

    fmt.Println(a)

  }

a의 맨끝을 없앤다는 것은 처음부터 맨 끝에서 하나 뺀거 까지만 간다는 것이기 때문에 다음과 같이 작성해 줍니다.

이 때 출력 시켜보죠.

처음 RemoveBack을 하면 10이 없어지고, 그 다음은 9가 없어지고, 그 다음은 8, 7....해서 5번을 돌기 때문에 남은건 1,2,3,4,5입니다.

 

좀 더 확실히 알기위해 없어지는 과정을 찍어보면 이렇습니다.

이번에는 맨 뒤에 값을 없애는데 맨 뒤에 값을 반환하는 함수를 만들어보죠.

  package main

  import "fmt"

  func RemoveBack(a []int) ([]int, int) {
    return a[:len(a)-1], a[len(a)-1]
  }

  func main() {
    a := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

    for i := 0; i < 5; i++ {
      var back int
      a, back = RemoveBack(a)
      fmt.Printf("%d, ", back)
    }
    fmt.Println()
    fmt.Println(a)

  }

함수에서 return값이 다중으로 나오면 위와 같이 ()로 묶어 주어야 하고, 맨 뒤에 값은 back으로 받고 출력시켜 줍니다.

없어진 맨 뒤에 숫자들이 출력되는 것을 알 수 있습니다.

 

그러면 이제는 맨 앞에 값을 없애보죠.

  package main

  import "fmt"

  func RemoveBack(a []int) ([]int, int) {
    return a[:len(a)-1], a[len(a)-1]
  }

  func RemoveFront(a []int) ([]int, int) {
    return a[1:], a[0]
  }

  func main() {
    a := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

    for i := 0; i < 5; i++ {
      var front int
      a, front = RemoveFront(a)
      fmt.Printf("%d, ", front)
    }
    fmt.Println()
    fmt.Println(a)

  }

RemoveFront()를 만들어서 마찬가지로 없어진 슬라이스와 맨 앞에 값을 반환하도록 해줍니다.

a의 맨 앞을 빼고 그 다음 부터인 인덱스 2번째부터 끝까지 반환하면 되고, 없어진 맨 앞에 값은 인덱스 0번째 값 부터 이므로 위와 같이 해줍니다.

이거는 실제로 메모리 상에서 사라지게 하는 것은 아니라는 점을 다시 한번 알아 두어야 합니다.

아까도 말했지만 그냥 가리키는 포인터만 바뀌게 되는 것입니다.

728x90
반응형
그리드형

댓글을 달아 주세요