Rust에서 문자열 이해하기: `String` vs 문자열 리터럴 (`&str`)
발행: (2026년 2월 21일 오후 05:07 GMT+9)
4 분 소요
원문: Dev.to
Source: Dev.to
문자열 리터럴 (&str)
- 컴파일 시점에 알려진 고정된, 불변의 UTF‑8 바이트 시퀀스.
- 프로그램 바이너리(읽기 전용 정적 메모리)에 직접 저장됨.
- 사용 비용이 제로: 컴파일러가 바이트를 삽입하고, 런타임에는 두께 포인터(포인터 + 길이)만 스택이나 레지스터에 생성됨.
- 수명은
'static– 프로그램 전체 기간 동안 존재함.
let s: &str = "hello";
"hello"는 실행 파일의 읽기 전용 데이터 섹션에 배치됨.- 힙 할당도, 시스템 콜도 없으며 – 포인터와 길이만 존재함.
String
- 힙에 할당되는 가변적이고 소유된 UTF‑8 버퍼.
- 수정 가능(e.g.,
push_str,push). - 스택에 저장되는 세 부분으로 구성: 힙 버퍼에 대한 포인터, 길이, 용량.
let s = String::from("hello");
- 힙에 메모리를 할당하고
"hello"를 복사한 뒤, 버퍼의 수명을 자동으로 관리함(스코프를 벗어나면 해제됨).
비교
| 항목 | &str (문자열 리터럴) | String |
|---|---|---|
| 변경 가능성 | 불변 | 가변 |
| 메모리 위치 | 읽기 전용 바이너리 섹션(정적) | 힙(가변) |
| 생성 방법 | "hello" 또는 &"hello" | String::from("hello") |
| 성능 | 접근 빠르고 할당 없음 | 힙 할당 때문에 느림 |
| 주요 사용 사례 | 정적 텍스트, 함수 매개변수 | 동적 문자열 구성 |
저장 세부 정보
| 타입 | 저장 위치 | 상세 |
|---|---|---|
&str | 읽기 전용 바이너리 섹션 | 포인터 + 길이가 일시적으로 스택에 존재하고, 바이트는 실행 파일에 내장됨. |
String | 힙 | 가변 버퍼; 포인터, 길이, 용량은 스택에 저장됨. |
할당 및 런타임 비용
| 타입 | 힙 할당 여부 | 상대 속도 |
|---|---|---|
&'static str | ❌ 없음 | 매우 빠름 |
String | ✅ 있음 | 느림(힙 연산) |
문자열 리터럴이 “할당이 더 빠른” 것이 아니라, 런타임 힙 할당을 전혀 하지 않기 때문입니다.
예시: 문자열 리터럴 사용
let s = "hello"; // `s`는 `&'static str` 타입
"hello"의 바이트는 이미 바이너리의 일부로 포함되어 있음.- 런타임에 Rust는 스택에 작은 참조(포인터 + 길이)만 생성함.
예시: String 생성
let s = String::from("hello");
- 힙 메모리를 할당하고 바이트를 복사한 뒤, 메타데이터를 스택에 저장함.
- 스코프를 벗어나면 버퍼가 자동으로 해제됨.
요약
&str– 불변, 컴파일 시점에 알려짐, 정적 읽기 전용 메모리에 저장, 참조 비용이 제로.String– 가변, 힙에 할당, 크기 조절 가능, 할당 오버헤드가 발생.
이 차이를 이해하면 상황에 맞는 타입을 선택할 수 있습니다: 정적 텍스트와 함수 인자는 &str을, 가변적이고 동적으로 구성되는 문자열은 String을 사용하세요.