Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

슬라이스(Slices)

Vec의 메모리 레이아웃을 다시 한 번 떠올려 볼까요?

let mut numbers = Vec::with_capacity(3);
numbers.push(1);
numbers.push(2);
      +---------+--------+----------+
스택  | 포인터  | 길이   | 용량     | 
      |  |      |   2    |    3     |
      +--|------+--------+----------+
         |
         |
         v
       +---+---+---+
힙:    | 1 | 2 | ? |
       +---+---+---+

이미 앞에서 String이 실제로는 Vec<u8>을 감싼 형태라는 것을 언급했었죠. 그렇다면 자연스럽게 이런 궁금증이 생길 수 있습니다. “Vec에 대응하는 &str 같은 타입은 없을까?”

&[T]

[T]는 타입 T의 연속된 요소 시퀀스를 나타내는 **슬라이스(Slice)**입니다. 주로 빌려온 형태인 &[T]를 가장 많이 사용하게 됩니다.

Vec에서 슬라이스 참조를 생성하는 방법은 여러 가지가 있습니다.

let numbers = vec![1, 2, 3];
// 인덱싱 구문을 사용하여 전체 슬라이스 참조 let slice: &[i32] = &numbers[..];
// 전용 메소드를 사용하여 슬라이스 참조 let slice: &[i32] = numbers.as_slice();
// 요소 중 일부만을 포함하는 슬라이스 참조 let slice: &[i32] = &numbers[1..];

Vec[T] 타입을 대상으로 Deref 트레이트를 구현하고 있습니다. 따라서 역참조 강제 변환(Deref coercion) 덕분에 Vec에서 슬라이스 전용 메소드를 직접 호출할 수 있습니다.

let numbers = vec![1, 2, 3];
// 놀랍게도, `iter`는 `Vec`의 메소드가 아닙니다!
// `&[T]`의 메소드이지만 역참조 강제 변환 덕분에 `Vec`에서도 바로 사용할 수 있죠.
let sum: i32 = numbers.iter().sum();

메모리 레이아웃(Memory Layout)

&[T]&str과 마찬가지로 **팻 포인터(fat pointer)**입니다. 슬라이스의 첫 번째 요소를 가리키는 포인터와 슬라이스의 길이라는 두 가지 정보로 구성됩니다.

요소가 세 개인 Vec이 있다고 가정해 봅시다.

let numbers = vec![1, 2, 3];

Vec의 일부분에 대한 슬라이스 참조를 만들면 다음과 같습니다.

let slice: &[i32] = &numbers[1..];

메모리 레이아웃은 다음과 같은 구조를 가집니다.

                  numbers                          slice
      +---------+--------+----------+      +---------+--------+
스택  | 포인터  | 길이   | 용량     |      | 포인터  | 길이   |
      |    |    |   3    |    4     |      |    |    |   2    |
      +----|----+--------+----------+      +----|----+--------+
           |                                    |  
           |                                    |
           v                                    | 
         +---+---+---+---+                      |
힙:      | 1 | 2 | 3 | ? |                      |
         +---+---+---+---+                      |
               ^                                |
               |                                |
               +--------------------------------+

&Vec<T>&[T]

함수 인자로 Vec에 대한 불변 참조를 넘겨야 할 때, 가급적 &Vec<T>보다는 &[T]를 사용하는 것이 좋습니다. &[T]를 사용하면 Vec뿐만 아니라 모든 종류의 슬라이스를 인자로 받을 수 있어 함수의 범용성이 높아지기 때문입니다.

예를 들어, Vec의 일부 요소를 전달하거나 **배열(array)**의 일부를 슬라이스로 전달할 수도 있습니다.

let array = [1, 2, 3];
let slice: &[i32] = &array;

배열의 슬라이스와 Vec의 슬라이스는 동일한 타입입니다. 둘 다 메모리상에 연속적으로 나열된 요소를 가리키는 팻 포인터일 뿐입니다. 배열의 경우 포인터가 힙(heap)이 아닌 스택(stack) 영역을 가리키게 되지만, 슬라이스를 사용하는 방식에는 아무런 차이가 없습니다.

Exercise

The exercise for this section is located in 06_ticket_management/10_slices