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가 사용되기 때문