다른 언어들은 프로그래머가 직접 명시적으로 메모리 할당 및 해제
러스트는 제3의 접근법 이용
- 러스트의 각각의 값은 해당값의 owner라고 불리는 변수를 가짐
- 한번에 딱 하나의 오너만 존재
- 오너가 스코프 밖으로 벗어날때, 값은 버려짐(dropped)
{ // s는 유효하지 않습니다. 아직 선언이 안됐거든요.
let s = "hello"; // s는 이 지점부터 유효합니다.
// s를 가지고 뭔가 합니다.
} // 이 스코프는 이제 끝이므로, s는 더이상 유효하지 않습니다.
let s1 = String::from("hello");
let s2 = s1;
println!("{}, world!", s1);
error[E0382]: use of moved value: `s1`
--> src/main.rs:4:27
|
3 | let s2 = s1;
| -- value moved here
4 | println!("{}, world!", s1);
| ^^ value used here after move
|
= note: move occurs because `s1` has type `std::string::String`,
which does not implement the `Copy` trait
let s1 = String::from("hello");
let s2 = s1.clone();
println!("s1 = {}, s2 = {}", s1, s2);
let x = 5;
let y = x;
println!("x = {}, y = {}", x, y);
요약
컴파일 타임에 결정되는 스택 메모리만 이용하는 변수들은 (=) 사용 가능
스택에 저장할 수 있는 타입은 Copy 트레잇 라고 불리우는 어노테이션 소유(트레잇은 이후에 소개)
copy 가능 타입
fn main() {
let s1 = gives_ownership(); // gives_ownership은 반환값을 s1에게
// 이동시킵니다.
let s2 = String::from("hello"); // s2가 스코프 안에 들어왔습니다.
let s3 = takes_and_gives_back(s2); // s2는 takes_and_gives_back 안으로
// 이동되었고, 이 함수가 반환값을 s3으로도
// 이동시켰습니다.
} // 여기서 s3는 스코프 밖으로 벗어났으며 drop이 호출됩니다. s2는 스코프 밖으로
// 벗어났지만 이동되었으므로 아무 일도 일어나지 않습니다. s1은 스코프 밖으로
// 벗어나서 drop이 호출됩니다.
fn gives_ownership() -> String { // gives_ownership 함수가 반환 값을
// 호출한 쪽으로 이동시킵니다.
let some_string = String::from("hello"); // some_string이 스코프 안에 들어왔습니다.
some_string // some_string이 반환되고, 호출한 쪽의
// 함수로 이동됩니다.
}
// takes_and_gives_back 함수는 String을 하나 받아서 다른 하나를 반환합니다.
fn takes_and_gives_back(a_string: String) -> String { // a_string이 스코프
// 안으로 들어왔습니다.
a_string // a_string은 반환되고, 호출한 쪽의 함수로 이동됩니다.
}
참조자(References)와 빌림(Borrowing)
fn main() {
let s1 = String::from("hello");
let len = calculate_length(&s1);
println!("The length of '{}' is {}.", s1, len);
}
fn calculate_length(s: &String) -> usize {
s.len()
}
가변 참조자(Mutable References)
let mut s = String::from("hello");
let r1 = &s; // 문제 없음
let r2 = &s; // 문제 없음
let r3 = &mut s; // 큰 문제
error[E0502]: cannot borrow `s` as mutable because it is also borrowed as
immutable
--> borrow_thrice.rs:6:19
|
4 | let r1 = &s; // 문제 없음
| - immutable borrow occurs here
5 | let r2 = &s; // 문제 없음
6 | let r3 = &mut s; // 큰 문제
| ^ mutable borrow occurs here
7 | }
| - immutable borrow ends here
댕글링 참조자(Dangling References)
포인터가 있는 언어에서는 잘못하면 댕글링 포인터를 만들기 쉬움
댕글링 포인터 : 어떤 메모리를 가리키는 포인터가 잇는동안, 그 메모리를 해제함으로써 다른 개체에게 사용하도록 줘버렸을지 모를 메모리를 참조하고 있는 포인터. 쉽게 해제된 메모리를 참조 중
아래 예제에서, 라이프 타임 때문에 댕글링 포인터가 생김
fn main() {
let reference_to_nothing = dangle();
}
fn dangle() -> &String {
let s = String::from("hello");
&s
}
error[E0106]: missing lifetime specifier
--> dangle.rs:5:16
|
5 | fn dangle() -> &String {
| ^^^^^^^
|
= help: this function's return type contains a borrowed value, but there is no
value for it to be borrowed from
= help: consider giving it a 'static lifetime
error: aborting due to previous error
슬라이스
소유권을 갖지 않는 데이터 타입
스트링 슬라이스
fn main() {
let s = String::from("hello world");
let hello = &s[0..5];
let world = &s[6..11];
}
let a = [1, 2, 3, 4, 5];
let slice = &a[1..3];