함수 호출은 하고 싶은데 번거롭게 소유권 이동은 피하고 싶은 상황. (소유권을 사용하려면 함수 호출할 때마다 반환값을 받아와야 한다.)
이렇게 매번 불필요한 소유권 이동을 피하고자 사용하는 개념이 '소유권 임대' !
'&' 를 붙이면 된다.
fn main() {
let s = String::from("헬로");
let len = string_length(&s); // s의 소유권은 넘어가지 않는다. 잠시 빌려주는 것일 뿐.
println!("{}의 길이 = {}", s, len); // 반환받지 않고도 그대로 s를 사용가능하다 (왜? 애초에 소유권이 넘어간 적이 없었기 때문)
}
fn string_length(s: &String) -> usize { // 받을 때도 '&' 써줘야 한다. (참조값) -> 참조로 받겠다
let length = s.len();
length
}
참조값이라는 건 소유자는 내가 아닌 다른 누군가라는 것.
참조값은 기본적으로 불변이다. (참조로는 값을 변경할 수 없다)
하지만 mutable 참조로 선언하면 참조값인데도 값을 변경할 수 있게 된다.(&mut String)
=> 함수 호출, 리시버 양쪽 다 mut으로 선언해줘야 함
=> 변경이 가능하게 하려면 mut을 붙여주면 된다.
(단, mut 참조는 단 하나만 만들 수 있다. 일반 참조끼리는 여러개 있어도 되지만 mut 참조가 생기는 경우 바로 배타적이 되어 다른 참조는 사용할 수 없게 된다. (일반 참조 + mut 참조 불가능)
(딱 하나라도 가변 참조가 끼면 나머지는 다 쓸 수 없게 된다.)
But
참조가 여러 번이더라도 블록은 물론이고 범위가 겹치지 않으면 가능하다.
범위가 겹치지 않으면 여러 번 중복 사용도 가능한데 여기서 말하는 범위는 그 참조값이 사용되는 공간임. (실제 사용되는 범위)
즉, 이 경우는 불가능하나
fn main() {
let mut s = String::from("헬로");
let r1 = &s; // 일반 참조1
let r2 = &s; // 일반 참조2
println("r1 = {}, r2 = {}", &r1, &r2);
let r3 = &mut s; // 가변 참조
println!("r1 = {}, r2 = {}, r3 = {}", &r1, &r2, &r3); // r3 사용 불가.
}
fn main() {
let mut s = String::from("헬로");
let r1 = &s; // 일반 참조1
let r2 = &s; // 일반 참조2
println("r1 = {}, r2 = {}", &r1, &r2); // 사용 가능
let r3 = &mut s; // 가변 참조
println!("r3 = {}", &r3); // 사용 가능. r3를 쓰되, r1,r2에 접근을 안 하면 됨.
}
꼭 블록({ })이 없더라도
코드 순서만으로도 해당 참조값을 사용하는 범위를 설정해서 구분한다.
범위가 겹치지 않으면 사용이 가능하나,
여기서 말하는 범위는 함수나, 스코프({}) 가 아닌 단지 코드의 순서도 해당된다.
(윗줄에서는 사용하고 그 다음줄에서는 사용하지 않는다면 범위가 끝난 것임)
일부 소유권 임대
슬라이스 타입

튜플 중에, 문자열 중에, .. 등등 일부만 참조하고 싶을 경우에 사용!
전체의 일부를 소유권 임대해서 참조할 수 있게 된다.
(슬라이스를 사용하면 일부 영역 참조가 가능하다~)
// 문자열 슬라이스 범위 표현
fn main() {
let s = String::from("헬로 월드");
let len = s.len();
let hello = &s[0..6];
let hello = &s[..6];
let world = &s[7..13];
let world = &s[7..];
let all = &s[..];
}
// Array 슬라이스 (배열의 일부 영역 참조)
let a = [1, 2, 3, 4, 5];
let slice = &a[1..3];
println!("a = {:?}, slice = {:?}", a, slice);