Today
-
Yesterday
-
Total
-
  • 러스트에서 문자열을 효과적으로 연결하기
    Programmer/Programming 2019. 2. 8. 17:41

    러스트(rust)에서 문자열을(&String or &str)을 연결(concatenation)하는 방법에는 여러가지가 있다.

    • SliceConcatExt::concat() -> String
    • SliceConcatExt::join(sep: &str) -> String
    • Add::add(rhs: &str) -> String
    • String::push_str(string: &str) -> String
    • write! and writteln! macros


    SliceConcatExt::concat() -> String

    문자열의 슬라이스(slice)에서 concat() 메서드를 호출하면 각 요소를 연결한 문자열을 생성한다.


    SliceConcatExt::join(sep: &str) -> String

    각 문자열 요소 사이에 지정된 구분 기호를 사용하여 문자열 배열의 모든 요소를 연결하는 함수다.
    우리는 모든 문자열을 단순 연결할 예정임으로 빈 문자열을 전달한다.


    다음 두가지는 String 메서드를 사용하여 문자열을 합칠 예정이다.
    러스트에서 mut 키워드가 붙은 String은 자바(Java)의 StringBuilder와 비슷하다.


    Add::add(rhs: &str) -> String

    String은 '+' 연산자를 오버로딩(overloading)하는 Add 트레이트(trait)를 구현하였다.
    String의 '+'는 자신의 뒤에 rhs를 추가하는 기능을 한다.


    String::push_str(string: &str) -> String

    String은 '+' 연산자와 동일한 역활을 한다.


    write!와 writeln! 매크로는 강력한 편리함을 제공하는 방식이다.

    use std::fmt::Write;
    
    let mut bld = String::new();
    writeln!(bld, "{} and {} are designed for writing to output stream.",
             "write!", "writeln!").unwarp();
    writeln!(bld, "They can append formatted text").unwrap();


    이 4가지 방법의 성능을 측정해보았다.
    마지막 두 개는 String::with_capacity(size: usize)를 사용하여 충분한 크기로 String을 생성한 뒤에 문자열을 연결했다.
    결과는 다음과 같다.(상대적인 차이만 보자)

     방법

     결과

     설명

     SliceConcatExt::concat()

     443 ns/iter (+/- 62)

     

     SliceConcatExt::join(sep: &str)

     459 ns/iter (+/- 49)

     매 요소마다 구분 기호를 추가함  

     Add::add(rhs: &str)

     1,078 ns/iter (+/- 106)

     버퍼를 초과할 때마다 크기를 늘려야 함[각주:1]

     String::push_str(string: &str)

     1,159 ns/iter (+/- 128)

     위와 마찬가지

     Add::add(rhs: &str) with capacity

     621 ns/iter (+/- 110)

     버퍼를 늘려야 하는 오버헤드 없음

     String::push_str(string: &str) with capacity 598 ns/iter (+/- 92)

     위와 마찮가지

     write! and writeln! macro 2,676 ns/iter (+/- 361) 

     매번 포맷 문자 확장이 필요함


    정리하면

    • 성능에 매우 민감하지 않으면 write!와 writeln! 매크로는 정말 편하다.
    • 성능이 매우 중요하면 SliceConcatExt::concat() 사용한다.
    • 문자열 요소 사이에 지정된 구분 기호가 필요하면 SliceConcatExt::join(sep: &str) 더 낫다.
    • Add::add(rhs: &str), String::push_str(string: &str) 사용할 때, 크기를 어느정도 예측할 수 있다면, 충분한 크기로 String을 생성한다.
    • 연결할 문자열을 언제까지 받을지 예측이 안되는 경우[각주:2]에는 Add::add(rhs: &str), String::push_str(string: &str)를 사용한다. Vec<String>이 너무 많은 메모리를 사용할 수 있다.[각주:3]


    1. 일반적으로 현재 크기의 두배로 늘림 [본문으로]
    2. 예를 들면, 네트워크를 통해 받을 때 [본문으로]
    3. 한국 러스트 컴뮤티니의 @Kroisse님이 알려줌.
      일반적으로는 concat()이나 push_str() 중에 아무것이나 사용해도 무방하다.
      성능에 영향을 줄 정도로 양이 늘어나면 https://crates.io/crates/ropey 사용을 고려한다. [본문으로]

    댓글

Designed by Tistory.