Rust
[Rust] Slice
yjk490
2024. 5. 2. 22:43
슬라이스(Slice)란?
- 컬렉션 요소에 대한 참조자
Slice가 없을 때의 컬렉션 사용
fn main() {
let mut s = String::from("hello world and yjk490");
let x = first_word(&s);
println!("{x}"); // 5 출력
s.clear(); // 변수 str을 비워서 ""으로 변경
}
fn first_word(s :&String) -> usize {
let bytes = s.as_bytes();
for (i, &item) in bytes.iter().enumerate() {
if (item == b' ') {
return i;
}
}
s.len()
}
- 공백으로 구분된 문자열을 매개변수로 받아 첫 번째 공백의 자리수를 반환하는 함수를 가정
- 컴파일은 정상적으로 된다. 그러나
str.clear()를 호출한 후x에 담긴 값은 더 이상str의 첫 번째 공백 자리수를 의미하지 않는다. - 따라서
x에 담긴 5를 사용해서str에서 첫 단어를 추출하는 데 사용할 경우 버그를 유발할 수 있음 - 이처럼 컬렉션의 특정 요소를 추출할 때, 이후 컬렉션 원본이 변경되면 컴파일에는 문제가 없지만 추출한 요소는 의미가 없어진다.
- 추출한 요소가 현재 컬렉션의 변경을 반영하고 있는지 계속 체크해야 하며, 추출한 요소는 데이터의 특정 상태에 의존하는 문제가 생긴다.
Slice의 사용
&기호와 함께 참조하고자 하는 시작 인덱스와 끝 인덱스를 명시let x = &y[0..3]- 0 부터 시작하면 시작 인덱스 생략 가능 `let x = &y[..3]
- 마지막 인덱스까지 참조하면 끝 인덱스 생략 가능
let x = &y[5..]
- 끝 인덱스에서 1을 뺀 인덱스까지 참조
- 내부적으로 시작 위치, 길이를 데이터 구조에 저장하며 길이 값은 끝 인덱스에서 시작 인덱스를 빼서 계산
- 원본 컬렉션이 수정되면 슬라이스도 영향을 받음
fn main() {
let mut s = String::from("hello world and yjk490");
let slice_1 = &s[0..5];
let slice_2 = &s[6..11];
println!("{slice_1}"); // hello 출력
println!("{slice_2}"); // world 출력
}

Slice를 통해 컬렉션 사용
fn main() {
let mut s = String::from("hello world and yjk490");
let x = first_word_by_slice(&s);
// 아래 코드 주석 해제 시, 컴파일 에러 발생
// s.push_str("test");
println!("{x}");
}
fn first_word_by_slice(s :&String) -> &str { // &str은 문자열 슬라이스 타입
let bytes = s.as_bytes();
for (i, &item) in bytes.iter().enumerate() {
if item == b' ' {
return &s[0..i];
}
}
&s[..] // 공백이 없으면 전체 문자열 슬라이스 반환
}
x에는 문자열 슬라이스가 저장되어 있으므로 원본 문자열이 변경되면x에도 반영된다.s.push_str("test")코드 사용 시 컴파일 에러 발생s는 가변 참조자인데push_str()호출 이후 같은 스코프 내에서 불변 참조자x가 사용되기 때문- Rust에서는 불변 참조자가 있으면 가변 참조자를 생성할 수 없다.
- 원본 문자열이 변경된 뒤 문자열 슬라이스가 사용되는 것을 문법적으로 방지한다.