슬라이스의 개념을 알아보기 전에 다음 예제를 먼저 살펴보겠습니다.
스트링을 입력 받아서 첫번째 공백 전까지의 단어를 반환하는 함수를 작성해봅니다.
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 |