6장 - 텍스트

문자열

  • 문자열은 언제나 유니코드
  • 문자열의 자료형은 &'static str
    • &는 메모리 내의 장소를 참조하겠다는 것
      • &mut가 빠졌다는 것은 컴파일러가 값의 변경을 허용하지 않을 것임
    • 'static은 string 데이터가 프로그램이 끝날 때까지 유효하다는 의미
      • Never DROP
    • str은 언제나 유효한 utf-8인 바이트 열
fn main() { let a: &'static str = "hi 🦀"; println!("{} {}", a, a.len()); }
💡
메모리 상세 문자열을 프로그램 메모리의 데이터 세그먼트에 저장함

utf-8이란 무엇인가

  • utf-8은 1에서 4 바이트의 가변 길이 바이트로 사용 가능한 문자의 범위를 늘림
    • 가변 길이 바이트 = 불필요한 바이트 X
  • 단점
    • 단순한 인덱싱 (ex> my_text[3])으로 문자를 찾을 수 없음
      • 문자마다 바이트 크기가 다르기 때문
    • utf-8 바이트 열을 하나하나 돌면서 유니코드 문자가 어디부터 시작하는지 찾아야 함
    • O(1) → O(n)
  • 🐠🐙🐟🐬🐋

예외처리문자

  • \n - 줄바꿈
  • \r - 캐리지리턴
  • \t - 탭
  • \\ - 역슬래시
  • \0 - null
  • \' - 작은 따옴표
fn main() { let a: &'static str = "Ferris가 말하길:\t\"안녕하세요\""; println!("{}", a); }

여러 줄로 된 문자열

  • Rust의 문자열은 기본적으로 여러 줄
  • 줄바꿈 문자를 원하지 않을 경우 \ 사용
fn main() { let haiku: &'static str = " 나는 쓰고, 지우고, 다시 쓴다 다시 지우고, 그러고 나면 양귀비 꽃이 핀다. - 가쓰시카 호쿠사이"; println!("{}", haiku); println!( "hello \ world" ) // w 앞의 공백이 무시 되었음을 주의하세요 }

원시 문자열

  • r#"로 시작, "#로 끝
  • 문자열을 있는 그대로 쓰는데 사용
fn main() { let a: &'static str = r#" <div class="advice"> 원시 문자열은 일부 상황에서 유용합니다. </div> "#; println!("{}", a); }

파일에서 문자열 가져오기

  • include_str! 매크로를 사용하여 로컬 파일에서 텍스트 로드
let 00_html = include_str!("00_ko.html");

문자열 슬라이스

  • 문자열 슬라이스는 메모리 상의 바이트 열에 대한 참조
  • 언제나 유효한 utf-8 바이트가 되어야 함
  • &str의 흔히 사용되는 메소드
    • len은 문자열의 바이트 길이를 가져옴
    • starts_with/ends_with는 기본적인 비교에 사용
    • is_empty는 길이가 0일 경우 true
    • find는 주어진 텍스트가 처음 등장 위치인 Option<usize> 값을 리턴
    • fn main() { let a = "hi 🦀"; println!("{}", a.len()); let first_word = &a[0..2]; let second_word = &a[3..7]; let char_idx = match a.find("🦀") { None => -1, Some(v) => v as i32, }; println!("{}", char_idx); // let half_crab = &a[3..5]; 실패 // Rust는 유효하지 않은 유니코드 문자열의 slice를 허용하지 않습니다 println!("{} {}", first_word, second_word); }

문자

  • utf-8 바이트 열을 char 자료형의 벡터로 돌려주는 기능을 제공
  • char 자료형은 하나의 크기가 4 bytes
    • fn main() { // 문자열을 char의 vector로 가져옵니다 let chars = "hi 🦀".chars().collect::<Vec<char>>(); let bytes_len = chars.len() * std::mem::size_of::<char>(); println!("{}", chars.len()); // 4여야 합니다 println!("{}", bytes_len); // 16 // char가 4 바이트이므로 u32로 변환할 수 있습니다 println!("{}", chars[3] as u32); // 하나씩 문자 및 바이트 값 출력 for ch in chars { println!("{}\t| 0x{:0>8x}", ch, ch as u32); } }
 

String

  • String은 heap memory에 저장된 utf-8 바이트 열을 소유하는 struct
  • → heap에 있기 때문에, 문자열과는 달리 늘리거나 변경 가능
  • 자주 쓰는 메소드
    • push_str string의 맨 뒤에 utf-8 바이트 추가
    • replace utf-8 바이트 열을 다른 것으로 교체
    • to_lowercase/to_uppercase 대소문자 변경
    • trim 공백 제거
  • String이 drop 되면, 그 heap memory도 함께 drop
  • &str 값으로 확장후 자신을 리턴하는 + 연산자 제공
    • fn main() { let mut helloworld = String::from("hello"); helloworld.push_str(" world"); helloworld = helloworld + "!"; println!("{}", helloworld); }

함수의 매개변수로서의 텍스트

  • 문자열(&'static str)과 String은 일반적으로 함수에 문자열 슬라이스 형태로 전달
  • → 소유권을 넘길 필요가 없어 대부분의 경우에 유연성 제공
fn say_it_loud(msg: &str) { println!("{}!!!", msg.to_string().to_uppercase()); } fn main() { // say_it_loud는 &'static str을 &str로 대여할 수 있습니다 say_it_loud("hello"); // say_it_loud는 또한 String을 &str로 대여할 수 있습니다 say_it_loud(&String::from("goodbye")); }

스트링 만들기

  • concat과 join 으로 String 만들기
fn main() { let helloworld = ["hello", " ", "world", "!"].concat(); let abc = ["a", "b", "c"].join(","); println!("{}", helloworld); println!("{}", abc); }

스트링 양식 만들기

  • format! 매크로 문자열 내 {} 를 파라메터로 하여 String 생성
  • format!은 println!과 동일한 매개변수화 된 string을 사용
fn main() { let a = 42; let f = format!("삶, 우주, 그리고 모든 것에 대한 해답: {}", a); println!("{}", f); }

스트링 변환

  • to_string을 이용하여 String으로 변환
  • parse로 string이나 문자열을 다른 자료형으로 변환 → Result 리턴
fn main() -> Result<(), std::num::ParseIntError> { let a = 42; let a_string = a.to_string(); let b = a_string.parse::<i32>()?; println!("{} {}", a, b); Ok(()) }
Float32 자료형 형변환 예제
fn main() -> Result<(), std::num::ParseFloatError> { // <- Error 타입 주의! let pi = 3.14159; let pi_string = pi.to_string(); let pi2 = pi_string.parse::<f32>()?; // <f32> 부동 소수점 타입으로 지정 println!("{} {}", pi, pi2); Ok(()) }

The Rust Programming Language 링크