문제의 역사
러스트에는 두 가지 주요 문자열 유형이 있습니다 — &str (슬라이스 문자열, 변경 불가능하며, 일반적으로 문자열 리터럴)과 String (동적이고, 변경 가능한 문자열). 언어 개발 초기 단계에서 이들 간의 선택은 효율적인 메모리 작업을 단순화하고 텍스트 데이터를 처리할 때 타입 안전성을 제공할 수 있게 했습니다. 이는 소유권과 참조의 엄격한 시스템 덕분입니다.
문제
많은 개발자들이 이 두 타입 간의 상호작용에 혼란을 겪습니다. 예를 들어, 문자열 리터럴은 &'static str, 즉 컴파일 시에 할당된 불변 문자열에 대한 참조인 반면, String은 동적으로 확장되며 런타임 시에 얻은 데이터를 포함할 수 있습니다. 따라서 이들 타입 간의 변환 방법, 소유권을 올바르게 사용하는 방법 및 불필요한 복사를 피하는 방법에 대한 질문이 종종 발생합니다.
해결책
&str과 String 간의 변환은 소유권의 기본 규칙을 이해하면 투명합니다:
String에서 슬라이스를 얻으려면 참조(my_string.as_str()) 또는 단순 대여(&my_string)를 사용하면 됩니다.&str을 String으로 변환하려면 to_string() 또는 String::from()을 사용합니다.코드 예:
fn main() { let s_literal: &str = "hello"; let s_string: String = String::from(s_literal); let s_slice: &str = &s_string; let new_string = s_slice.to_string(); println!("{} {}", s_string, new_string); }
주요 특징:
&str은 힙 메모리를 차지하지 않으며 항상 변경 불가능합니다.String은 동적으로 메모리를 할당할 수 있으며 변경 가능합니다.러스트에서 문자열 리터럴을 수정할 수 있나요?
아니요, 문자열 리터럴(&'static str)은 항상 변경 불가능하며, 문자를 수정하려는 시도는 컴파일 단계에서 오류를 발생시킵니다.
&str에서 .to_string()을 호출하는 것으로 불필요한 복사 없이 변경 가능한 문자열을 얻을 수 있나요?
아니요, .to_string()은 항상 새로운 메모리를 할당하고 내용을 복사합니다. 이는 슬라이스 기반의 변경 가능한 문자열이 필요할 때 피할 수 없는 일입니다.
String에서 &str 참조를 생명 주기 오염 없이 얻을 수 있나요?
네, 이렇게 얻은 참조(let s: &str = &my_string;)는 원래의 String보다 오래 살지 않습니다. 함수에서 로컬 String에서 &str을 반환하려고 하면 생명 주기 오류가 발생합니다.
String에 대한 &str 참조를 보존&str을 String으로 변환 (불필요한 할당 발생)String::from("text")가 데이터 복사를 생성하지 않을 것이라고 기대함수가 함수 내의 임시 String에 대한 &str 참조를 반환합니다:
fn faulty() -> &str { let s = String::from("Oops"); &s // 생명 주기 오류! }
장점:
단점:
함수가 즉시 String을 반환하고 호출자에게 소유권을 전달합니다:
fn correct() -> String { String::from("Safe!") }
장점:
단점: