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

문자열 슬라이스 (String Slices)

이전 장에서 "To-Do""A ticket description"처럼 코드 안에 적힌 **문자열 리터럴(String literals)**을 많이 보셨을 겁니다. 그리고 항상 그 뒤에 .to_string()이나 .into()가 따라왔었죠. 이제 그 이유를 알아볼 때입니다!

문자열 리터럴 (String Literals)

따옴표로 감싸서 텍스트를 정의하면 그것이 문자열 리터럴입니다.

let s = "Hello, world!";

여기서 s의 타입은 &str이며, 이는 문자열 슬라이스에 대한 참조입니다.

메모리 레이아웃 (Memory Layout)

&strString은 서로 다른 타입이며 마음대로 바꿔 쓸 수 없습니다. String의 메모리 구조를 다시 떠올려 봅시다.

let mut s = String::with_capacity(5);
s.push_str("Hello");

위 코드를 실행하면 메모리 구조는 다음과 같아집니다:

      +---------+--------+----------+
스택  | 포인터  | 길이   | 용량     | 
      |  |      |   5    |    5     |
      +--|------+--------+----------+
         |
         |
         v
       +---+---+---+---+---+
힙:    | H | e | l | l | o |
       +---+---+---+---+---+

그리고 &StringString의 메타데이터가 저장된 스택 주소를 가리키는 포인터였죠. 그렇다면 문자열 전체가 아니라 Helloello처럼 일부만 가리키고 싶을 때는 어떻게 해야 할까요?

문자열 슬라이스 (String Slices)

&str은 문자열의 특정 부분을 비추는 **뷰(View)**이자, 어딘가에 저장된 UTF-8 바이트 시퀀스를 가리키는 **참조(Reference)**입니다.

let mut s = String::with_capacity(5);
s.push_str("Hello");
// 첫 번째 바이트를 건너뛰고 문자열 슬라이스를 만듭니다.
let slice: &str = &s[1..];

메모리에서는 이렇게 표현됩니다:

                    s                              slice
      +---------+--------+----------+      +---------+--------+
스택  | 포인터  | 길이   | 용량     |      | 포인터  | 길이   |
      |    |    |   5    |    5     |      |    |    |   4    |
      +----|----+--------+----------+      +----|----+--------+
           |        s                           |  
           |                                    |
           v                                    | 
         +---+---+---+---+---+                  |
힙:      | H | e | l | l | o |                  |
         +---+---+---+---+---+                  |
               ^                                |
               |                                |
               +--------------------------------+

slice는 스택에 두 가지 정보를 담습니다:

  1. 슬라이스의 시작점을 가리키는 포인터
  2. 슬라이스의 길이

slice는 데이터를 소유하지 않고 그저 가리킬 뿐입니다. slice가 사라져도 힙에 있는 실제 데이터는 여전히 s가 소유하고 있으므로 해제되지 않습니다. 그래서 slice에는 capacity(용량) 필드가 없습니다. 자기가 데이터를 소유한 것이 아니니 용량을 알 필요가 없는 것이죠.

&str vs &String

함수를 만들 때 텍스트 데이터를 참조로 받고 싶다면, 특별한 이유가 없는 한 &String보다는 &str을 쓰시는 것이 좋습니다. &str이 훨씬 유연하고 관용적인 표현(Idiomatic)이기 때문입니다.

메서드가 &String을 반환한다면, 어딘가에 정확히 그 내용과 일치하는 힙 할당 UTF-8 데이터가 있음을 보장하는 셈입니다. 반면 &str을 반환하는 것은 “어딘가에 데이터 뭉치가 있고, 그중에서 당신이 필요한 부분이 여기 있으니 보세요“라고 말하는 것과 같아서 훨씬 자유롭습니다.

Exercise

The exercise for this section is located in 04_traits/06_str_slice