프로그래밍풀스택 개발자

러스트에서 변경 불가능한 문자열과 동적 타입 String은 어떻게 작동하나요? String과 &str의 차이점은 무엇이며, 소유권은 어떻게 작동하고 이러한 타입 간의 안전한 변환은 어떻게 이루어지나요?

Hintsage AI 어시스턴트로 면접 통과

답변.

문제의 역사:

네이티브 언어(C/C++)와 비교할 때, 러스트는 참조 타입(&str)과 소유 타입(String) 간의 엄격한 분리를 통해 안전한 문자열 작업을 제공합니다. 이는 잘못된 메모리, 버퍼 오버플로우 및 더블 프리와 관련된 대부분의 오류를 제거합니다.

문제:

성숙한 GC 언어들과 달리, 러스트에서는 문자열이 누가 소유하고 있고, 얼마 동안 살아있으며, 수정 후에 어떤 잘못된 참조를 피해야 하는지를 명확히 이해해야 합니다. UTF-8 문자열 작업은 인덱싱과 수정할 때 주의가 필요합니다.

해결책:

러스트에서 String은 내용물을 소유하는 변경 가능한 힙 할당 문자열입니다. &str은 UTF-8 보장을 가진 바이트 시퀀스에 대한 변경 불가능한 참조입니다. 필요에 따라 std의 메서드를 사용하여 안전하게 변환할 수 있습니다 (&str -> String 및 그 반대).

코드 예시:

fn main() { let owned: String = String::from("Rust"); let borrowed: &str = &owned; let primitive: &str = "Hello"; // 리터럴은 항상 &str // &str -> String 변환 let s: String = primitive.to_string(); // String -> &str 변환 let st: &str = &s; println!("{} {} {} {}", owned, borrowed, primitive, st); }

주요 특징:

  • 소유와 참조 간의 명확한 구분 (힙 vs 슬라이스)
  • String과 &str 간의 안전 변환 메서드는 효율적이며 객체의 수명에 대해 투명합니다.
  • 문자열 리터럴은 항상 &'static str 타입을 가지며, String이 아닙니다.

속임수 질문.

왜 문자열을 s[1] 또는 s[i]처럼 인덱싱할 수 없나요?

러스트의 문자열은 UTF-8이므로 직접적으로 인덱싱할 수 없습니다: s[i]는 i번째 문자를 반환하지 않으며, 때때로 잘못된 바이트 경계에 접근할 때 panic을 유발합니다. 대신, .chars().nth(i) 또는 .get(start..end) 메서드를 사용하세요.

&str를 안전하게 수정할 수 있나요?

안 됩니다 - &str은 항상 변경 불가능한 슬라이스입니다. 수정을 원할 경우 to_owned/to_string을 사용하거나 String/Vec<u8>을 사용하세요.

String::from("abc")와 "abc".to_string()의 원리는 무엇이 다른가요?

이 두 가지는 결과적으로 동등하며, 둘 다 &str에서 데이터를 복사하여 String을 생성합니다. 차이는 스타일에 있습니다: 예를 들어, to_string은 ToString 트레이트를 통해 구현되며, String::from은 "소유권 생성" 의도를 더 명확하게 표현합니다.

일반적인 오류 및 안티 패턴

  • 문자열을 s[1] 또는 s[0]으로 인덱싱하여 char를 얻으려는 시도
  • 수명 지정 없이 암시적 변환: 임시 객체에 대한 참조 반환
  • &str로 충분한 곳에 String을 사용하는 것 (불필요한 할당)

실제 사례

부정적인 경우

함수가 String을 받아 내부에서 불필요하게 문자열을 복사(clone)한 다음, 다른 함수에 slice를 쓰면서 원본의 수명을 늘리는 것을 잊었습니다. 결과: dangling reference & crash.

장점:

  • 익숙한 언어와 유사하게: 쉽게 문자열의 "복사본"을 얻을 수 있습니다.

단점:

  • 불필요한 할당으로 인한 성능 손실
  • 임시 값에 대한 참조 누수 가능성

긍정적인 경우

함수가 &str을 받아 수정이 필요할 경우 내부에서 .to_string()을 호출하고, 외부에서는 모든 로직이 "zero copy"로 유지됩니다. 수명은 제어되며, 불필요한 할당이 없습니다.

장점:

  • 높은 성능
  • 소유권 오류 방지

단점:

  • 수명과 소유권에 대한 이해가 필요
  • 초보자에게 약간 더 많은 인지적 부담이 있음