slices는 collection의 연속된 일부를 참조할 수 있게 해준다. slice는 reference(참조)의 한 종류이므로 소유권을 갖지 않는다. 예시로 String에서 첫 번째 단어의 끝부분의 인덱스를 찾는 함수를 만들었다.
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()
}
String
요소 하나하나를 보면서 그 값이 공백인지 확인할 필요가 있기 때문에, String
을 as_byte
메소드를 이용하여 바이트 배열로 변환한다. 다음으로 iter
메소드를 이요하여 바이트 배열의 반복자(iterator)를 생성한다. enumerate
메소드가 튜플을 반환하고 요소의 참조자를 갖기 위해서 &
을 패턴 내에 사용했다.
String
의 첫 번째 문자를 저장하고 있는데 해당 String
이 삭제되는 상황을 가정해보자.
fn main() {
let mut s = String::from("hello world");
let word = first_word(&s); // word will get the value 5
s.clear(); // this empties the String, making it equal to ""
// word still has the value 5 here, but there's no more string that
// we could meaningfully use the value 5 with. word is now totally invalid!
}
s
가 삭제되어도 word
는 이후에 접근이 가능하다. 이런 상황이 error를 유발할 수 있다. rust에서는 string slice으로 해결할 수 있다.
string sclice는 String
일부분에 대한 reference이다. 우리는 [starting_index..ending_index]
형태로 range를 특정한다. 다른 range와 마찬가지로 starting_index는 포함되고 ending_index는 포함되지 않는다. &str
은 slice의 일종으로 볼 수 있으며, &str
이 왜 immutable한 reference인지 추측할 수 있다.
let s = String::from("hello world");
let hello = &s[0..5];
let world = &s[6..11];
let world = &s[6..11];
의 경우, world
는 s
의 6번째 바이트를 가리키고 길이값 5를 갖고 잇는 슬라이스가 될 것이다.
- range를 표현할 때, index 0부터 시작하면 앞을 비워도 된다.
let slice = &s[0..2];
let slice = &s[..2];- 반대로 마지막 바이트를 포함할 때는 끝을 비워도 된다.
let slice = &s[3..len];
let slice = &s[3..];- 모든 String이 ASCII코드라는 가정 하에 이루어진다. 만약 multibyte character를 이용한다면, 이곳에서 정보를 얻을 수 있다.
이러한 정보를 바탕으로 코드를 수정해보자.
let mut s = String::from("hello world");
let word = first_word(&s);
s.clear(); // error!
println!("the first word is: {}", word);
fn first_word(s: &String) -> &str {
let bytes = s.as_bytes();
for (i, &item) in bytes.iter().enumerate() {
if item == b' ' {
return &s[0..i];
}
}
&s[..]
}
이제는 String을 삭제하면 compile error 가 발생한다.
fn main() {
let mut s = String::from("hello world");
let word = first_word(&s);
s.clear(); // error!
println!("the first word is: {}", word);
}
rust는 String을 삭제하기 위해서 가변 참조자를 부른다 하지만, 우리는 이미 참조자를 갖고 있기 때문에, 컴파일 에러를 내며 프로그램이 종료된다.
slice에는 다양한 타입이 존재한다. Array
타입 또한 마찬가지이다.
let a = [1, 2, 3, 4, 5];
let slice = &a[1..3];
assert_eq!(slice, &[2, 3]);