String

  • str, &str: 어딘가 저장된 UTF-8로 인코딩된 스트링 데이터의 참조자.
  • String: 핵심 언어 기능 내 구현된게 아님. 표준 라이브러리를 통해 제공.

생성하기

let mut s = String::new();

let data = "initial contents";
let s = data.to_string();

let s = "initial contents".to_string();

let s = String::from("initial contents");
  • to_string은 Display 트레잇이 구현된 어떤 타입이든 사용이 가능하다.
  • 스트링 리터럴(str)은 Display 트레잇을 구현하고 있다.
  • 따라서 str은 to_string 메소드로 String 생성이 가능.
  • String::from 을 이용해서 스트링 리터럴(str)로 String 생성 가능.

UTF-8

let hello = String::from("السلام عليكم");
let hello = String::from("Dobrý den");
let hello = String::from("Hello");
let hello = String::from("שָׁלוֹם");
let hello = String::from("नमस्ते");
let hello = String::from("こんにちは");
let hello = String::from("안녕하세요");
let hello = String::from("你好");
let hello = String::from("Olá");
let hello = String::from("Здравствуйте");
let hello = String::from("Hola");
  • 스트링은 UTF-8로 인코딩된다.

push

let mut s = String::from("foo");
s.push_ptr("bar");
let mut s1 = String::from("foo");
let s2 = "bar";
s1.push_str(&s2);
println!("s2 is {}", s2);
let mut s = String::from("lo");
s.push('l'); // lol

+ 연산자

let s1 = String::from("Hello, ");
let s2 = String::from("world!");
let s3 = s1 + &s2; // s1은 여기서 소유권이 이동되어 사용할 수 없게된다.
  • + 연산자 이후 s2가 아닌 &s2를 사용하는 이유는 add 오퍼레이트의 매개변수에서 s: &str을 받기 때문임.
// 주의! 실제 표준 라이브러리에서 add는 제네릭으로 정의되어 있음.
fn add(self, s: &str) -> String { ... }
  • add 메소드에서 self가 소유권을 가져가기 때문에 s1은 add 호출 후 더 이상 유효하지 않게된다.
  • 위 구문은 복사본을 만들지 않는다. 하지만 빠르다!

format! 매크로

let s1 = String::from("tic");
let s2 = String::from("tac");
let s3 = String::from("toe");

let s = s1 + "-" + &s2 + "-" + &s3;
let s = format!("{}-{}-{}", s1, s2, s3});
  • format!은 매크로다.
  • 연산자를 사용하는것 보다 읽기 쉽고 파라미터들의 소유권을 가져가지 않는다!

인덱싱

let s1 = String::from("hello");
let h = s1[0]; // 에러: std::string::String` cannot be indexed by `{integer}let len = String::from("Hola").len();
  • String은 인덱스로 접근하여 문자를 얻을 수 없다.
  • String을 통하여 인덱스로 문자를 얻게 만들면 상수시간 O(1)에 실행되지 못할것이다. 스트링 내에 얼마나 많은 문자가 있는지 파악하기 위해서 시작 지점부터 끝까지 훑어야 하기 때문이다.

String의 내부

String::from("Hola").len(); // 4
String::from("한글").len(); // 6
String::from("Здра").len(); // 8
  • String은 Vec<u8>을 감싼 것이다.

문자소 클러스터(Grapheme cluster)

  • Rust가 문자열을 다음 3가지 관점으로 본다:
    1. 바이트
    2. 스칼라 값
    3. 문자소 클러스터
// 데바가나리 글자로 쓰여진 힌디어 “नमस्ते”

/* 1. Vec<u8> */
[224, 164, 168, 224, 164, 174, 224, 164, 184, 224, 165, 141, 224, 164, 164,
224, 165, 135]

/* 2. char(스칼라) */
['न', 'म', 'स', '्', 'त', 'े'] // 4, 6번째 문자는 발음 구별 부호다.

/* 3. 문자소 클러스터 */
["न", "म", "स्", "ते"]

스트링 슬라이싱

  • String이 바이트, 캐릭터, 문자소 클러스트인지 알 수 없으므로, 스트링 인덱싱은 주의해서 사용해야한다.
let hello = "Здравствуйте";
let s = &hello[0..4];
  • s는 스트링의 첫 4바이트를 담는 &str이 된다.
  • hello에서 글자하나가 2바이트를 차지하므로, s는 “Зд” 가 된다.
  • &hello[0..1] 은 panic을 발생시킨다.

스트링 내 반복

for c in "नमस्ते".chars() {
    println!("{}", c);
}
// 결과:






for b in "नमस्ते".bytes() {
    println!("{}", b);
}
// 결과:
224
164
168
224
164
174
224
164
184
224
165
141
224
164
164
224
165
135
  • 스트링으로부터 문자소 클러스터를 얻는 방법은 복잡하므로 표준 라이브러리에서 제공하지 않는다.

참고자료