Rust에서 문자열 다루기: 메소드와 활용법
Rust에서 문자열은 데이터 조작의 중요한 부분입니다. Rust는 안전성과 효율성을 유지하면서 문자열을 조작할 수 있는 다양한 기능과 메소드를 제공합니다. 이 글에서는 **Rust 문자열 타입(String, &str)**의 주요 차이점과 이를 조작하는 다양한 방법을 논리적으로 정리하고, 상세히 설명하겠습니다.
1. Rust 문자열의 두 가지 주요 타입
1.1 String
- 힙(heap)에 저장되며, **가변적(mutable)**이고 **소유권(ownership)**을 가집니다.
- 문자열 데이터를 동적으로 추가, 수정, 삭제할 수 있습니다.
let mut s = String::from("Hello");
s.push_str(", world!"); // 문자열 추가
println!("{}", s); // 출력: Hello, world!
1.2 &str (String Slice)
- **불변(immutable)**이며, 문자열 데이터의 일부분을 참조합니다.
- 런타임에 생성된 String과 달리 컴파일 타임에 고정된 문자열(리터럴)을 주로 다룹니다.
let s = "Hello, Rust!"; // &str 타입
println!("{}", s); // 출력: Hello, Rust!
2. 문자열 생성 및 초기화
Rust에서는 String
을 다양한 방식으로 생성할 수 있습니다.
2.1 String::new()
- 빈 문자열을 생성합니다.
let mut s = String::new();
s.push_str("Rust is awesome!");
println!("{}", s); // 출력: Rust is awesome!
2.2 String::from()
- 문자열 리터럴에서 String 객체를 생성합니다.
let s = String::from("Hello, Rust!");
println!("{}", s); // 출력: Hello, Rust!
2.3 to_string()
- 문자열 리터럴 또는 다른 타입의 데이터를 String으로 변환합니다.
let s = "Hello".to_string();
let num = 42.to_string();
println!("{}, {}", s, num); // 출력: Hello, 42
3. 문자열 조작 메소드
Rust는 문자열 조작을 위한 다양한 메소드를 제공합니다.
3.1 추가 및 연결
3.1.1 push
- 단일 문자(char)를 추가합니다.
let mut s = String::from("Rust");
s.push('!');
println!("{}", s); // 출력: Rust!
3.1.2 push_str
- 문자열(&str)을 추가합니다.
let mut s = String::from("Hello");
s.push_str(", world!");
println!("{}", s); // 출력: Hello, world!
3.1.3 +
연산자와 format!
매크로
+
연산자로 문자열을 연결하거나,format!
을 사용해 포맷팅된 문자열을 생성합니다.
let s1 = String::from("Hello");
let s2 = String::from(", Rust!");
let s3 = s1 + &s2; // s1은 이동되고 더 이상 사용할 수 없음
println!("{}", s3); // 출력: Hello, Rust!
let s4 = format!("{} {}", "Hello", "world!");
println!("{}", s4); // 출력: Hello world!
3.2 변경 및 변환
3.2.1 replace
- 특정 문자열을 다른 문자열로 교체합니다.
let s = String::from("I love Java!");
let new_s = s.replace("Java", "Rust");
println!("{}", new_s); // 출력: I love Rust!
3.2.2 trim
- 문자열 양 끝의 공백을 제거합니다.
let s = String::from(" Rust programming ");
println!("{}", s.trim()); // 출력: Rust programming
3.2.3 to_uppercase
와 to_lowercase
- 문자열을 대문자 또는 소문자로 변환합니다.
let s = String::from("Rust");
println!("{}", s.to_uppercase()); // 출력: RUST
println!("{}", s.to_lowercase()); // 출력: rust
3.3 검색
3.3.1 contains
- 특정 문자열이 포함되어 있는지 확인합니다.
let s = String::from("Rust is fun");
println!("{}", s.contains("fun")); // 출력: true
3.3.2 starts_with
와 ends_with
- 문자열의 시작 또는 끝을 확인합니다.
let s = String::from("Rustacean");
println!("{}", s.starts_with("Rust")); // 출력: true
println!("{}", s.ends_with("acean")); // 출력: true
3.4 반복 및 슬라이싱
3.4.1 chars
와 split_whitespace
chars
는 문자열의 각 문자를 반복(iterate)하며,split_whitespace
는 공백을 기준으로 문자열을 나눕니다.
let s = String::from("Rust is great!");
for c in s.chars() {
print!("{} ", c); // 출력: R u s t i s g r e a t !
}
let words: Vec<&str> = s.split_whitespace().collect();
println!("{:?}", words); // 출력: ["Rust", "is", "great!"]
3.4.2 슬라이싱
- 문자열의 부분(slice)을 참조할 수 있습니다.
let s = String::from("Hello, Rust!");
let slice = &s[7..11]; // 7번 인덱스부터 10번 인덱스까지
println!("{}", slice); // 출력: Rust
4. 유니코드와 Rust 문자열
Rust 문자열은 **유니코드(UTF-8)**를 기본적으로 지원합니다. 따라서 이모지나 비ASCII 문자를 다룰 때도 문제없습니다.
let s = String::from("안녕하세요, Rust 🦀!");
for c in s.chars() {
println!("{}", c);
}
// 출력:
// 안
// 녕
// 하
// 세
// 요
// ,
//
// R
// u
// s
// t
// 🦀
F&Q: 문자열 다루기에서 자주 묻는 질문
Q1: Rust에서 String
과 &str
의 차이는 무엇인가요?
A1 :
String
: 힙(heap)에 저장되며 가변적이고 소유권을 가집니다. 동적으로 수정이 가능합니다.&str
: 불변적이며 문자열 데이터를 참조합니다. 주로 리터럴 문자열이나 다른 문자열의 슬라이스로 사용됩니다.
Q2: 문자열 추가는 어떻게 하나요?
A2 :
- 단일 문자 추가:
.push('c')
- 문자열 추가:
.push_str("text")
- 문자열 연결:
+
연산자 또는format!
매크로
let mut s = String::from("Hello");
s.push_str(", Rust!"); // 추가
let s2 = format!("{} world!", s); // 연결
println!("{}", s2); // 출력: Hello, Rust! world!
Q3: 문자열을 숫자로 변환할 수 있나요?
A3 :.parse()
메소드를 사용하면 문자열을 숫자로 변환할 수 있습니다. 이때 변환할 타입을 명시해야 합니다.
let num: i32 = "42".parse().unwrap();
println!("{}", num + 10); // 출력: 52
Q4: 문자열의 길이는 어떻게 구하나요?
A4 :
.len()
: 문자열의 바이트 길이 반환.chars().count()
: 문자열의 유니코드 문자 수 반환
let s = "안녕하세요";
println!("{}", s.len()); // 출력: 15 (바이트 길이)
println!("{}", s.chars().count()); // 출력: 5 (문자 길이)
Q5: Rust에서 문자열 슬라이스란 무엇인가요?
A5 :
문자열의 일부를 참조할 수 있는 &str
타입입니다. UTF-8 경계를 준수해야 하며, 안전하게 문자열의 일부분을 다룰 수 있습니다.
let s = String::from("Hello, Rust!");
let slice = &s[7..11]; // 슬라이스
println!("{}", slice); // 출력: Rust
이 5가지 질문은 Rust에서 문자열을 다룰 때 가장 자주 직면하는 문제를 해결해줍니다. 문자열 생성, 추가, 변환, 길이 측정, 슬라이싱을 활용해 효율적인 코드를 작성해 보세요!
결론
Rust에서 문자열 조작은 강력한 문자열 처리 도구와 다양한 문자열 메소드를 통해 안전하면서도 효율적으로 수행됩니다. String과 &str의 차이를 명확히 이해하고, 문자열 생성, 문자열 추가, 문자열 변환, 문자열 검색, 문자열 슬라이싱과 같은 다양한 문자열 조작 메소드를 적절히 활용하면, 복잡한 문자열 처리 작업도 간단히 해결할 수 있습니다. Rust의 UTF-8 지원과 메모리 안전성(memory safety)은 강력한 문자열 처리 성능을 제공합니다. 이러한 기능들을 마스터하여 안정적이고 효율적인 Rust 프로그래밍을 경험해 보세요. Rust 문자열 메소드를 잘 활용하면 더욱 강력하고 최적화된 Rust 코드를 작성할 수 있습니다!