Skip to content

Latest commit

 

History

History
192 lines (122 loc) · 4.81 KB

collection-string.md

File metadata and controls

192 lines (122 loc) · 4.81 KB

러스트의 스트링

러스트 코어는 스트링 슬라이스인 str만 제공한다.

String 타입은 표준 라이브러리를 통해 제공된다.

String 타입의 특성

  1. 가변적
  2. 소유권
  3. UTF-8 인코딩(어떤 문자라도 포함할 수 있다.)

새로운 스트링 만들기

new 함수로 비어있는 스트링을 생성할 수 있다.

let mut s = String::new();

to_string 메서드로 초기값이 있는 스트링을 만든다.

Display 트레잇이 구현된 타입은 모두 to_string 메서드 사용이 가능하다.

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

String::from 함수로도 스트링 리터럴에서 String을 생성할 수 있다.

let s = String::from("initial contents");

String::from.to_string은 기능이 똑같아서 어떤 것을 사용할 지는 개발자 마음이다.

스트링 갱신하기

push_str 메서드로 String을 늘릴 수 있다.

let mut s = String::from("foo");
s.push_str("bar");

push_str 메서드는 파라미터의 소유권을 가져올 필요가 없어서 스트링 슬라이스를 파라미터로 갖는다.

아래 코드에서 s2는 소유권이 보존돼서 오류가 나지 않는다.

let mut s1 = String::from("foo");
let s2 = "bar";
s1.push_str(&s2);
println!("s2 is {}", s2);

push로 문자 하나를 String에 추가할 수 있다.

let mut s = String::from("lo");
s.push('l');

+로 스트링 붙이기

+ 연산자로 두 개의 스트링을 조합할 수 있다.

let s1 = String::from("Hello, ");
let s2 = String::from("world!");
let s3 = s1 + &s2; // s1은 이동되어 유효하지 않아짐

+ 연산은 아래 처럼 생긴 add 메서드를 사용하는데 String&str을 더하는 형태이다.

fn add(self, s: &str) -> String {

&s2&String이지만 역참조 강제에 의해 &str로 강제 변환된다.

&s2&s2[..]로 바뀌는 것이다.

adds2의 소유권은 가져가지 않지만

&가 없는 selfs1을 인자로 받아서 s1의 소유권을 가져간다.

format! 매크로로 스트링 합치기

format! 매크로는 println!처럼 작동하면서 결과를 스크린에 출력하는 대신 String을 반환한다.

또한, format!은 파라미터의 소유권을 가져가지 않는다.

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

let s = format!("{}-{}-{}", s1, s2, s3);

스트링을 인덱싱로 접근하기

는 지원되지 않는다.

스트링의 내부적 표현

StringVec<u8>을 감싼 것이다.

아래의 len은 4인 반면

let len = String::from("Hola").len();

아래의 len은 12가 아닌 24이다.

let len = String::from("Здравствуйте").len();

각각의 유니코드 스칼라 값이 2바이트 씩 차지하기 때문이다.

바이트, 스칼라 값, 문자소 클러스터(우리가 보는 글자)

“नमस्ते” 이렇게 생긴 힌디어는 18바이트의 Vec<u8>로 저장된다.

[224, 164, 168, 224, 164, 174, 224, 164, 184, 224, 165, 141, 224, 164, 164, 224, 165, 135]

char 타입으로 본다면 이렇다.

['न', 'म', 'स', '्', 'त', 'े']

우리가 보는 글자처럼 문자로 클러스터로 보면 이렇다.

["न", "म", "स्", "ते"]

셋 중에 어떤게 유효한지는 문자열 내용을 모두 알아야 알 수 있다.

그래서 String의 인덱스 연산이 O(1) 성능이 보장되지 않는다.

스트링 슬라이스할 때는 조심

스트링 슬라이스를 만들 때는 스트링 인덱스로 접근하는 것과 같은 연산을 하면 안 된다.

아래는 괜찮은데

let hello = "Здравствуйте";

let s = &hello[0..4];

아래와 같이 하면 인덱스로 접근하는 것과 같아서 런타임에 패닉이 발생한다.

&hello[0..1]

스트링 요소 접근

1. 캐릭터로 반복하기(.chars())

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

2. 바이트로 반복하기(.bytes())

for b in "नमस्ते".bytes() {
    println!("{}", b);
}

3. 문자소 클러스터로 반복하기

방법이 복잡해서 라이브러리를 가져다 쓴다.

스트링이 복잡한 만큼 사용하기 까다롭다.

러스트가 다루기 까다로운데 본성이 복잡한 스트링은 러스트 내에서 다루기 더 까다롭다.

하지만, 까다로움 덕분에 개발 후반에 스트링 관련 에러를 마주할 일을 막을 수 있다.