[Rust]

[Rust] 슬라이스(slices)

극꼼 2023. 7. 27. 09:47
반응형


슬라이스의 개념을 알아보기 전에 다음 예제를 먼저 살펴보겠습니다.

스트링을 입력 받아서 첫번째 공백 전까지의 단어를 반환하는 함수를 작성해봅니다.

fn main() {
    let str = String::from("ab cde f g");
    let w = first_word_length(&str);
    println!("{}", w); //ab 2글자이므로 2 출력.

}

fn first_word_length(s:&String) -> usize {
    let bytes = s.as_bytes();
    for (i, &item) in bytes.iter().enumerate() {
        if item == b' '{
            return i;
        }
    }

    s.len()
}

first_word_length() 함수에서는 다음과 같은 과정을 거칩니다.

1. s 스트링을 as_bytes() 메서드를 통해 바이트 배열로 변환

2. iter() 메서드로 바이트 배열의 각 요소를 반환 => enumerate()로 iter의 결과값을 직접 반환하는 대신 이를 감싸서 튜플의 일부로 만들어 반환(i = 인덱스, &item = 한 바이트에 대응하는 참조값)

3. 바이트 리터럴 문법을 이용해서 공백 문자를 나타내는 바이트를 찾음

4. 찾을 경우 인덱스인 i를 리턴하고, 그렇지 않다면 s 스트링의 길이를 리턴

 

만약 first_word_length() 함수를 다음과 같이 사용한다면 버그가 발생합니다.

let mut str2 = String::from("hello world");
let word = first_word_length(&str2);
str2.clear();
println!("{}", word);

word는 str2와 직접적으로 연결되어 있지 않기 때문에 str2.clear() 이후에도 무리없이 5 값을 가지고 있습니다. 하지만 str2의 내용물이 변경된 후이기 때문에 이는 버그가 됩니다. 이러한 동기화 문제를 해결하기 위해 러스트에는 스트링 슬라이스(string slice)가 있습니다.


<슬라이스(slices)>

: 소유권을 갖지 않는 데이터 타입입니다. 슬라이스는 컬렉션(collection) 전체가 아닌 컬렉션의 연속된 일련의 요소들을 참조할 수 있게 합니다.

 

<스트링 슬라이스(string slice)>

: String의 일부분에 대한 참조자.

let str3 = String::from("hello world");

let hello = &str3[0..4];
let world = &str3[6..11];
println!("{}",hello); // hell 출력.

[start..end] 문법은 start부터 시작해서 end를 포함하지 않습니다. 만약 end까지 포함하도록 하고 싶다면 [start..=end] 로 입력해줍니다. 만약 0부터 시작한다면 [..4]와 같이 0을 생략해줘도 됩니다. 6부터 끝까지 포함한다면 [6..] 로 입력해줍니다. 만약 전체 스트링을 포함하는 슬라이스를 만들고 싶다면 [..] 둘 다 생략할 수 있습니다.

 

이제 처음에 했던 코드를 조금 바꿔서 첫번째 단어를 반환하는 함수를 작성해보겠습니다.

fn first_word_length2(s: &String) -> &str {
    let bytes = s.as_bytes();

    for (i, &item) in bytes.iter().enumerate() {
        if item == b' ' {
            return &s[0..i];
        }
    }

    &s[..]
}

first_word_length2 함수를 이용해서 스트링 값을 받을 경우, 값을 참조해서 받고있기 때문에 다음과 같이 str.clear()을 하면 에러가 뜹니다 : error[E0502]: cannot borrow `str` as mutable because it is also borrowed as immutable

let mut str = String::from("hello world");
let w = first_word_length2(&str);
str.clear();
println!("{}", w); // 에러 출력

스트링 리터럴 = 슬라이스 입니다.

let str = "ab cde f g";

str 변수의 타입은 &str로, 바이너리의 특정 지점을 가리키고 있는 슬라이스입니다. &str은 불변 참조자이기 때문에 스트링 리터럴도 불변입니다. 위에서 적은 first_word_length2 함수는 다음과 같이 적을 수도 있습니다.

fn first_word_length2(s: &str) -> &str {

<그 외의 슬라이스>

다음은 i32타입의 배열에 대한 슬라이스입니다.

let a = [1,2,3,4,5];
let slice = &a[1..3];

요약한 참조 링크 : https://rinthel.github.io/rust-lang-book-ko/ch04-03-slices.html

반응형

'[Rust]' 카테고리의 다른 글

[Rust] 구조체 - 메서드  (0) 2023.07.30
[Rust] 데이터 구조체  (0) 2023.07.29
[Rust] 참조자(References)와 빌림(Borrowing)  (0) 2023.07.26
[Rust] 소유권  (0) 2023.07.25
[Rust] 제어문  (0) 2023.07.20