문자열 타입

문자열 타입

Rust에서 문자열을 표현하기 위해 일반적으로 &str 타입과 String 타입을 사용한다.

&str 타입

str 타입은 문자열을 표현하는 Primitive 문자열 타입이다. str 타입은 (1) 문자열 리터럴을 변수에 할당하거나 (&'static str 타입), (2) 다른 변수가 소유한(owned) 문자열의 일부를 슬라이스하여(&str 타입) 가져올 때 사용된다. str 타입은 항상 레퍼런스이기 때문에, 실제 코드에서는 &str 와 같이 사용된다. 문자열 리터럴은 코드 바이너리에 직접 저장되고, 프로그램의 실행기간 동안 계속 존재하여 'static 이라는 키위드가 추가된다.

문자열을 표현할 때, 가장 많이 보게 되는 표현은 아마 아래와 같이 문자열 리터럴(string literal)을 쓰는 경우일 것이다. 이때 문자열 리터럴을 가리키는 변수 s는 &str 타입이다.

fn main() {
    let s = "hello";    // let s: &'static str = "hello"; 와 동일
    println!("{}", s);
}

위 예제에서 변수 s는 &'static str 타입으로 문자열 리터럴 "hello" 에 대한 레퍼런스(reference)이다. &str의 &는 레퍼런스를 의미하고, 여기서 문자열 리터럴 전체를 가리킨다.

슬라이스(slice)는 데이타의 일부 범위(range)를 지정하여 전체 중 일부만을 가져오는 것으로, 예를 들어 아래 예제에서 &s[1..4] 는 요소1 부터 요소3까지의 범위 즉 "ell" 을 가리킨다. 범위(range)를 지정할 때 [시작..마지막] 와 같이 표현하는 마지막위치는 실제 마지막위치의 다음 인덱스를 넣는다. 즉, 마지막위치가 3이면 4를 넣는다.

fn main() {
    let s = "hello";  
    let sub: &str = &s[1..4];
    println!("{}", sub);    // "ell" 출력
}

위 예제는 변수 s가 소유한(own) 문자열의 일부 범위를 문자열 슬라이스하여 변수 sub에 넣는 예제이다. 변수 sub의 타입은 &str 타입으로서 이 타입을 보통 문자열 슬라이스(string slice)이라고도 부른다.

&str 타입을 (아래에 설명하는) String 타입으로 변환하기 위해서는 to_owned() 함수를 사용한다. (주: to_string()은 임의의 타입을 String 타입으로 변환하는 것인데, 더 많은 메모리를 사용하므로 &str 타입에서는 to_owned() 함수를 사용하는 것이 좋다)

fn main() {
    let s: &'static str = "hello";  

    // &str 타입을 String 타입으로 변환
    let x: String = s.to_owned();

    println!("{}", x);
}

&str 타입에는 일반 문자열을 처리할 때 사용되는 다양한 메서드들이 제공되고 있다. 아래는 &str 타입의 trim() 메서드와 to_lowercase() 메서드를 사용해 본 예제이다.

fn main() {
    let s: &str = "    HELP    ";  

    if s.trim().to_lowercase() == "help" {
        println!("### Help ###");
    }
}

[참고] 슬라이스 심도 학습

String 타입

String (std::string::String) 타입은 Heap 메모리 상에 문자열을 저장하는 타입으로, 문자열 메모리에 새 문자들을 추가하거나 수정할 수 있다. 즉, String 타입은 고정된 길이의 문자열이 아니라 크기를 증가시키거나 축소할 수 있는 문자열(growable String)이다.

"hello"를 출력하는 코드를 String 타입으로 표현해 보면 아래와 같이 쓸 수 있다. 여기서 String::from()은 문자열 리터럴으로부터 String 타입의 문자열을 만드는 함수이다. (동일한 기능을 하는 함수로서 문자열 리터럴(&str)의 to_owned() 함수를 사용할 수도 있다.)

fn main() {
    let s = String::from("hello");  // 문자열 리터럴을 String 타입으로 
    // let s: String = "hello".to_owned(); // 동일

    println!("{}", s);
}

String 타입을 처음 생성하기 위해서는 String::new()를 사용할 수 있다. 처음에는 빈 문자열이므로 여기에 문자들을 추가하기 위해 변수를 mut로 만들어 주었으며, 문자를 추가하는 push() 함수와 문자열을 추가하는 push_str() 함수를 사용하였다.

fn main() {
    let mut s = String::new();   // empty string 생성
    s.push('H');           // 문자 추가
    s.push('i');           // 문자 추가
    s.push_str(" Tom");  // 문자열 추가
    
    println!("{}", s);  // "Hi Tom" 출력
}

문자열의 일부를 다른 문자들로 치환하기 위해서는 String::replace() 함수를 사용할 수 있다. 아래 예제는 replace() 함수를 사용하여 변수 s에서 Hello 라는 문자열을 Hi 로 변경하여 Hi Bill을 출력하는 코드이다.

fn main() {
    let mut s = String::from("Hello Bill");
    s = s.replace("Hello", "Hi");
    
    println!("{}", s); // "Hi Bill" 출력
}

아래 예제는 문자열에 공백문자가 있는지를 체크하기 위해 String::contains() 함수를 사용한 후, 공백(혹은 다른 whitespace)으로 분리(split_whitespace)하여 각 단어를 출력하는 예이다.

fn main() {
    let s = String::from("Hello World");    
    
    if s.contains(" ") {      // 공백 체크 
        for w in s.split_whitespace() {  // whitespace로 분리
            println!("{}", w);
        }
    }
}

[참고] Rust 심도학습 => 문자열의 UTF-8 인코딩

This site is not affiliated with or endorsed by the Rust Foundation or Rust Project.