Updated:

4 minute read

개요

  • 가비지 콜렉터 없이 메모리 안정성 보장
  • 컴파일 타임에 컴파일러가 체크할 규칙들로 구성된 소유권 시스템을 통해 메모리 관리
  • 런타임 비용이 발생하지 않음
  • 참조자(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