ABOUT ME

-

Total
-
  • Rust 문법: Ownership (소유권)
    컴퓨터/Rust 2021. 4. 24. 20:33
    728x90
    반응형

    Rust

     

    Rust Programming Language

    A language empowering everyone to build reliable and efficient software.

    www.rust-lang.org

     

    1. 소개

    수많은 언어에 존재하지 않는 Rust만의 특징인, ownership, borrowing이란 개념이 있다.

    (포인터처럼 접근해서 생각하면 편할 것이다.)

    코어 콘셉트는 다음과 같다.

    • 데이터는 오직 하나의 소유자를 가질 수 있다.
    • 빌려간 데이터는 exclusive mutable이거나 shared immutable이다.

    ex) 변수 a를 지정 후 b가 a를 지정하면 a를 사용불가 상태가 된다.

    y가 x의 1 소유권 갖고 있음

    위와 같은 코드를 실행하면 x는 1을 가리키고, y도 1을 가리키는 stack에서 새로 생성된다.

     

    대부분 언어처럼 해도 a를 쓰든 b를 쓰든 상관없지만, Rust에선 아래처럼 포인터가 움직여

    기본적으로 a를 사용할 수 없게 된다. (deep clone을 하게 되면 새롭게 포인터가 복사됨)

    # Python
    a = "hello"
    b = a
    
    // Rust
    let a = String::from("hello");
    let b = a;

    Rust: y가 hello 소유권자

     

    2. Ownership 예제

    아래의 경우 drop_me 함수를 부른 후 x를 다시 사용할 수 없다.

    main 스택에서 x가 생성되고 heap에 "hello"가 생성된다.

    drop_me를 부를 때 소유권을 s에게 넘겨주고 drop_me에서 소유권을 다시 넘겨주지 않았다. (no return)

    drop_me가 stack frame에서 사라지고 "hello"의 소유권도 사라져 버려서 x를 출력하고 싶어도 아래와 같은 오류가 난다.

    Rust 컴파일러의 오류는 직관적이다.

    fn drop_me(s: String) {}
    
    fn main() {
        let x = String::from("hello");
        drop_me(x);
    
        println!("{}", x);
    }

     

    위 코드에서 소유권을 돌려받고 싶으면, 새롭게 변수를 생성해야 한다.

    x는 쓸 수 없다.

    fn give_me_back(s: String) -> String{
        s
    }
    
    fn main() {
        let x = String::from("hello");
        let y = give_me_back(x);
    
        println!("{}", y);
    }

     

    3. Borrowing 예제

    변수는 위처럼 소유권을 한 명만 가질 수 있지만 도서관 책처럼 빌려갈 수 있다.

    V언어, Rust같이 몇몇 언어에선 모든 변수가 기본적으로 immutable이다.

     

    아래 예제는 소유권을 한 번 빌리고 다시 받은 상태에서 단순히 소유권을 넘기고 빌리는 건 안된다.

    struct Book {}
    
    fn borrow(b: &Book) {}
    fn give(b: Book) {}
    
    fn main() {
        let book = Book{};
        
        borrow(&book);  // 빌리기
        give(book);  // 소유권 전달
        borrow(&book);  // 또 빌리기, ERROR
        // value borrowed here after move
    }

     

    lifetime 중에 데이터를 빌릴 수 있는 방법은 아래와 같다.

    • immutable borrows: &T, (multiple 하게 빌릴 수 있음, 하지만 그 누구도 mutable 접근이 없어야 함)
    • mutable borrows: &mut T, (하나의 mutable 빌린 값만 존재할 수 있음)

     

    아래 코드를 보면 book.borrow() 부분에서 mutable borrow가 발생했다고 오류가 난다.

    그 이유는 위의 두 가지 규칙에 의하면 borrow는 book의 mutable borrow를 만들지만

    이미 Shop에 존재하는 immutable borrow를 mutable borrow로 overlap 되어서 2번째 규칙에 어긋난다.

    struct Book {
        name: String,
        taken: bool,
    }
    
    impl Book {  // Book에 대한 메소드 만들기 OOP
        fn new(name: String) -> Self {
            Self{name:name, taken:false}
        }
    
        fn borrow(&mut self) {
            self.taken = true;
        }
    
    }
    
    struct Shop<'a> {  // the lifetime a으로 읽음
        book: &'a Book,
    }
    
    impl<'a> Shop<'a> {
        fn is_borrowed(&self) -> bool {
            self.book.taken
        }
    }
    
    fn main() {
        let book = Book::new("Harry Poter".into());
        let shop = Shop { book: &book };  // immutable borrow occurs here
    
        println!("{}", book.name);
    
        book.borrow();  // mutable borrow occurs here
    
        if shop.is_borrowed() {  // immutable borrow later used here
            println!("The {} is already borrowed", book.name);
        } else {
            println!("Borrowing {}...", book.name);
        }
    }

     

     

    참고

    공식 문서 (What is ownership): doc.rust-lang.org/book/ch04-01-what-is-ownership.html

     

    What is Ownership? - The Rust Programming Language

    Rust

    doc.rust-lang.org

    Ownership, Borrowing에 대한 괜찮은 영상: www.youtube.com/watch?v=8M0QfLUDaaA

     

    728x90

    댓글