[Rust] 소유권
Updated:
개요
- 가비지 콜렉터 없이 메모리 안정성 보장
- 컴파일 타임에 컴파일러가 체크할 규칙들로 구성된 소유권 시스템을 통해 메모리 관리
- 런타임 비용이 발생하지 않음
- 참조자(references)
- &를 사용하여 값을 참조하지만 소유하지는 않는 참조자를 생성
- 참조자가 가리키는 값은 참조자가 스코프 밖으로 벗어났을 때도 메모리가 반납되지 않음
- 빌림(borrowing)
- 함수의 파라미터로 참조자를 만드는 것
- 변수와 마찬가지로 기본적으로는 불변, mut를 사용하면 가변
- 가변 참조자(mutable references)
- &mut를 사용하여 가변성을 부여한 참조자
- 특정 스코프내에 하나만 생성 가능
- 불변 참조자를 가지고 있을 동안에도 생성 불가
- 불변 참조자를 사용하는 동안 값이 변경되면 않되므로 생성 불가
- 불변 참조자는 여러개 생성 가능
- 댕글링 참조자(dangling references)
- 컴파일러가 모든 참조자들이 댕글링 참조자가 되지 않도록 보장
- 컴파일러는 참조자가 스코프 밖으로 벗어나기 전에는 데이터가 스코프 밖으로 벗어나지 않을 것임을 확인
규칙
- 각각의 값은 해당값의 오너(owner)라고 불리는 변수를 갖는다
- 한번에 딱 하나의 오너만 존재 가능하다
- 오너가 스코프 밖으로 벗어나면 값은 버려진다(dropped)(drop 함수 호출)
예제 1
- 코드
-
fn main() { { let s1 = String::from("a"); let s2 = s1; println!("{}", s1); } }
-
- 실행 결과
-
error[E0382]: borrow of moved value: `s1` --> src/main.rs:6:24 | 3 | let s1 = String::from("a"); | -- move occurs because `s1` has type `String`, which does not implement the `Copy` trait 4 | let s2 = s1; | -- value moved here 5 | 6 | println!("{}", s1); | ^^ value borrowed here after move | = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider cloning the value if the performance cost is acceptable | 4 | let s2 = s1.clone(); | ++++++++ For more information about this error, try `rustc --explain E0382`. error: could not compile `test1` (bin "test1") due to previous error
-
예제 2
- 코드
-
fn main() { { let s1 = String::from("a"); let s2 = s1.clone(); println!("{}", s1); println!("{}", s2); } }
-
- 실행 결과
-
a a
-
예제 3
- 코드
-
fn f1(s: String) { println!("{}", s); } fn main() { let s = String::from("a"); f1(s); println!("{}", s); }
-
- 실행 결과
-
error[E0382]: borrow of moved value: `s` --> src/main.rs:8:20 | 6 | let s = String::from("a"); | - move occurs because `s` has type `String`, which does not implement the `Copy` trait 7 | f1(s); | - value moved here 8 | println!("{}", s); | ^ value borrowed here after move | note: consider changing this parameter type in function `f1` to borrow instead if owning the value isn't necessary --> src/main.rs:1:10 | 1 | fn f1(s: String) { | -- ^^^^^^ this parameter takes ownership of the value | | | in this function = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider cloning the value if the performance cost is acceptable | 7 | f1(s.clone()); | ++++++++ For more information about this error, try `rustc --explain E0382`. error: could not compile `test1` (bin "test1") due to previous error
-
예제 4
- 코드
-
fn f1(s: String) -> String { s } fn main() { let s = String::from("a"); let s = f1(s); println!("{}", s); }
-
- 실행 결과
-
a
-
예제 5
- 코드
-
fn f1(s: &String) { println!("{}", s); } fn main() { let s = String::from("a"); f1(&s); println!("{}", s); }
-
- 실행 결과
-
a a
-
예제 6
- 코드
-
fn f1(s: &String) { s.push_str(", b"); } fn main() { let s = String::from("a"); f1(&s); println!("{}", s); }
-
- 실행 결과
-
error[E0596]: cannot borrow `*s` as mutable, as it is behind a `&` reference --> src/main.rs:2:5 | 2 | s.push_str(", b"); | ^^^^^^^^^^^^^^^^^ `s` is a `&` reference, so the data it refers to cannot be borrowed as mutable | help: consider changing this to be a mutable reference | 1 | fn f1(s: &mut String) { | +++ For more information about this error, try `rustc --explain E0596`. error: could not compile `test1` (bin "test1") due to previous error
-
예제 7
- 코드
-
fn f1(s: &mut String) { s.push_str(", b"); } fn main() { let mut s = String::from("a"); f1(&mut s); println!("{}", s); }
-
- 실행 결과
-
a, b
-
예제 8
- 코드
-
fn main() { let mut s = String::from("a"); let s1 = &mut s; let s2 = &mut s; println!("{}", s1); println!("{}", s2); }
-
- 실행 결과
-
error[E0499]: cannot borrow `s` as mutable more than once at a time --> src/main.rs:5:14 | 4 | let s1 = &mut s; | ------ first mutable borrow occurs here 5 | let s2 = &mut s; | ^^^^^^ second mutable borrow occurs here 6 | 7 | println!("{}", s1); | -- first borrow later used here For more information about this error, try `rustc --explain E0499`. error: could not compile `test1` (bin "test1") due to previous error
-
예제 9
- 코드
-
fn main() { let mut s = String::from("a"); { let s1 = &mut s; s1.push_str(", b"); println!("{}", s1); } let s2 = &mut s; s2.push_str(", c"); println!("{}", s2); }
-
- 실행 결과
-
a, b a, b, c
-
예제 10
- 코드
-
fn dangle() -> &String { let s = String::from("a"); &s } fn main() { println!("{}", dangle()) }
-
- 실행 결과
-
error[E0106]: missing lifetime specifier --> src/main.rs:1:16 | 1 | fn dangle() -> &String { | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from help: consider using the `'static` lifetime | 1 | fn dangle() -> &'static String { | +++++++ For more information about this error, try `rustc --explain E0106`. error: could not compile `test1` (bin "test1") due to previous error
-
예제 11
- 코드
-
fn not_dangle() -> String { let s = String::from("a"); s } fn main() { println!("{}", not_dangle()) }
-
- 실행 결과
-
a
-