Penflip

Penflip - Write better with others

  • Loading...
  • Discover Projects
  • Help
  • Signup
  • Login
  • Welcome back!
    No account? Signup Close
    Ready to write better?
    Have an account? Login Close

sarojaba · Rust Doc Korean

Make Changes
46

5.7. 소유권 (Ownership) - 100%

이 가이드는 러스트의 소유권 시스템을 설명하는 세 가이드 중 하나입니다. 이는 러스트의 가장 고유하면서 매력적인 동시에 러스트 개발자들이 반드시 친숙해져야 하는 특징입니다. 소유권을 통해 러스트는 스스로의 가장 거대한 목표인 메모리 안정성을 성취해냅니다. 관련된 몇가지 개념들이 있는데, 각각을 설명하는 장이 존재합니다. 다음과 같죠:

  • 여러분이 지금 읽고 계시는 소유권
  • 빌림, 그리고 관련된 특징인 '참조'
  • 수명, 빌림의 고급 개념

이 세 장들은 연관되어 있고, 순서대로 작성되어 있습니다. 소유권 시스템을 이해하기 위해선 세 장을 모두 필요로 할 것입니다.

메타

세부사항을 살펴보기 전에, 소유권 시스템에 관한 두 가지 중요한 점을 짚고 넘어가겠습니다.

러스트는 안정성과 속도에 초점을 맞추고 있고, 이러한 목표들을 많은 '무비용 추상화 zero-cost abstraction'들을 통해 이루어냅니다. 다시 말해, 러스트에서 추상화는 그것이 작동하기 위해 필요한 최소한의 비용만을 필요로 합니다. 소유권 시스템은 무비용 추상화의 대표적인 예입니다. 이 가이드에서 이야기할 모든 분석들은 _컴파일 타임 내에 _이루어집니다. 이러한 기능들을 사용하기 위해 런타임에서 비용을 치를 필요는 없다는 이야기죠.

하지만, 이 시스템 역시 치뤄야할 비용은 있기 마련인데, 바로 학습 곡선입니다. 러스트를 처음 접하는 많은 사용자들은 작성자는 아무 문제가 없다고 생각하는 프로그램을 러스트 컴파일러가 컴파일하기 거부하는 현상에 맞닥뜨립니다. 우리가 '소유권 검사기와의 싸움'이라고 부르는 현상이죠. 이는 보통 소유권이 어떻게 동작해야 하는 지에 대한 프로그래머의 생각과 실제 러스트가 구현하는 규칙들이 다르기 때문에 발생합니다. 이 글을 읽고 있는 당신도 처음엔 비슷한 경험을 할지 모릅니다. 좋은 소식은, 이러한 소유권 시스템 규칙들과 함께 작업을 하면 할수록 소유권 검사기와 싸울 일은 점점 적어진다고 다수의 숙련된 러스트 개발자들이 말한다는 거죠.

그걸 명심하시고, 소유권에 대해 배워봅시다.

소유권

러스트에서 변수 바인딩들은 그것들에 바인드 된 자원에 대한 '소유권을 가지고' 있습니다. 이것은 바인딩이 스코프를 벗어나면, 러스트는 바인드된 리소스를 해제할 것입니다. 예를 들어보죠:

fn foo() {
    let v = vec![1, 2, 3];
}

v가 스코프에 들어오면, 새로운 <code>Vec<T></code>가 생성됩니다. 또한 이 경우, 그 벡터는 세 개의 원소를 위한 공간을 힙 영역에 할당합니다. foo()의 끝부분에서 v가 스코프를 벗어나게 되면, 러스트는 이 벡터와 관련된 모든 것을 정리합니다. 힙 영역에 할당된 메모리까지 말이죠. 이러한 일은 스코프의 끝부분에서 결정론적으로 일어납니다.

이동 시맨틱

좀 더 미묘한 문제들이 있는데요. 러스트는 어떤 자원에 대해서건 정확히 하나의 바인딩만이 존재할것을 보장합니다. 예를 들어, 우리가 벡터를 하나를 가지고 있을 때, 그 벡터를 다른 바인딩에 할당할 수 있겠죠:

let v = vec![1, 2, 3];

let v2 = v;

하지만, 이 이후에 우리가 v를 사용하려 한다면:

let v = vec![1, 2, 3];

let v2 = v;

println!("v[0] is: {}", v[0]);

에러가 발생합니다. 이런식으로 말이죠:

error: use of moved value: `v`
println!("v[0] is: {}", v[0]);
                        ^

소유권을 가져가는 어떤 함수를 정의한 후, 그 함수에 인자로서 넘긴 무언가를 그 후에 사용하려 할 때도 비슷한 일이 일어납니다:

fn take(v: Vec<i32>) {
    // what happens here isn’t important.
}

let v = vec![1, 2, 3];

take(v);

println!("v[0] is: {}", v[0]);

같은 에러죠: '이동된 값의 사용 use of moved value'. 우리가 어떤 소유권을 다른 어딘가로 이전시킬 때, 우리는 그것을 '이동시켰다'고 말합니다. 이 작업은 러스트에 의해 알아서 행해지고, 따로 뭘 적을 필요는 없습니다.

세부사항

우리가 어떤 바인딩을 이동시킨 후부터는 그 바인딩을 사용할 수 없는 이유는 미묘하지만 중요합니다. 이런 코드를 생각해 보세요:

let v = vec![1, 2, 3];

let v2 = v;

첫 째 줄은 벡터 객체인 v와 거기 담겨 있는 데이터들을 위한 메모리를 할당합니다. 벡터 객체는 스택에 저장되고, 힙 영역에 저장되어 있는 내용물들([1, 2, 3])을 가리키는 포인터를 포함합니다. 우리가 v를 v2로 옮기면, v2가 사용할 그 포인터의 복사본이 생성됩니다. 다시 말해, 힙 영역에 있는 그 벡터의 내용물들을 가리키는 두 개의 포인터가 존재하는거죠. 이는 데이터 레이스를 발생시킴으로서 러스트의 안전 지침을 침해합니다. 따라서, 러스트는 이동이 일어난 후에는 v의 사용을 금지합니다.

또한, 스택 영역에 실제로 존재하는 복사본은 최적화 과정에서 삭제될 수 있다는 점에 유의하세요. 그렇기 때문에, 실제로는 이러한 시맨틱이 보이는 것만큼 비효율적이지는 않답니다.

Copy 타입

소유권이 다른 바인딩으로 넘어갈 경우 기존의 바인딩을 사용하지 못한다고 했었죠. 하지만, 이러한 행동 양식을 바꾸는 Copy라는 특성_trait_이 존재합니다. 우리는 특성들에 대해 아직 이야기하지 않았지만, 지금으로서는 특정 타입에 행동 양식을 추가하는 주석같은 존재라고 생각하세요. 예를 들어:

let v = 1;

let v2 = v;

println!("v is: {}", v);

이 경우에, v는 Copy 특성을 구현한 i32 타입입니다. 이동을 할 때와 마찬가지로 우리가 v2에 v를 할당할 때, 데이터의 복사본이 만들어집니다. 하지만 이동과는 다르게, 그 후에도 우리는 v를 사용할 수 있습니다. 이는 i32는 다른 곳에 있는 데이터로의 포인터를 가지고 있지 않아서 i32의 복사는 완전한 복사를 의미하기 때문에 그렇습니다.

모든 기본 타입은 Copy 특성을 구현하고 있고, ´소유권 규칙(ownership rules)´에 따라, 소유권은 이동하지 않습니다. 예를 들어, i32와 bool 타입은 Copy 특성을 구현했기 때문에 다음의 두 코드 조각은 컴파일 됩니다.

fn main() {
    let a = 5;

    let _y = double(a);
    println!("{}", a);
}

fn double(x: i32) -> i32 {
    x * 2
}
fn main() {
    let a = true;

    let _y = change_truth(a);
    println!("{}", a);
}

fn change_truth(x: bool) -> bool {
    !x
}

Copy 특성이 구현되지 않은 타입을 사용했다면, 이동할 수 있는 값을 사용하려고 했기에, 컴파일 오류를 얻을 것입니다.

error: use of moved value: `a`
println!("{}", a);
               ^

당신이 정의한 타입들이 Copy 특성을 가지게 하는 방법에 대해선 특성 섹션에서 살펴보도록 하겠습니다.

소유권을 넘어서

당연하지만, 만약 우리가 작성한 모든 함수에서 소유권을 반환해야 한다면:

fn foo(v: Vec<i32>) -> Vec<i32> {
    // do stuff with v

    // hand back ownership
    v
}

우리의 코드는 상당히 장황해 질 것입니다. 우리가 소유권을 가져오고 싶은 것들이 늘어날 수록 상황은 나빠지겠죠:

fn foo(v1: Vec<i32>, v2: Vec<i32>) -> (Vec<i32>, Vec<i32>, i32) {
    // do stuff with v1 and v2

    // hand back ownership, and the result of our function
    (v1, v2, 42)
}

let v1 = vec![1, 2, 3];
let v2 = vec![1, 2, 3];

let (v1, v2, answer) = foo(v1, v2);

아이구! 반환 타입, 반환 라인, 그리고 함수 호출 등이 모두 훨씬 복잡해 질 것입니다.

다행히도, 러스트는 이런 문제의 해결을 돕기 위해 빌림이라는 기능을 제공합니다. 다음 섹션의 주제죠!

Updated by sarojaba over 3 years (view history)
5.6. 반복 (Loops) - 100% 5.8. 참조와 빌림 (References and Borrowing) - 100%

Contents

    Rust 문서 한글화 프로젝트 1. 소개(Introduction) - 1.10.0 2. 시작하기(Getting Started) - 100% 3. Rust 배우기 (Learn Rust) - 100% 3.1. 추리 게임 (Guessing Game) - 100% 3.2. 식사하는 철학자들 (Dining Philosophers) - 100% 3.3. 다른 언어에 Rust 포함하기 (Rust Inside Other Languages) - 100% 4. 효과적인 Rust (Effective Rust) - 100% 4.1. 스택과 힙 (The Stack and the Heap) - 100% 4.2. 테스팅 (Testing) - 100% 4.3. 조건부 컴파일 (Conditional Compilation) - 70% 4.4. 문서화 (Documentation) - 20% 4.5. 반복자 (Iterators) - 100% 4.6. 동시성 (Concurrency) - 90% 4.7. 오류 처리 (Error Handling) - 4% 4.8. Choosing your Guarantees - 0% 4.9. 외부 함수 인터페이스 (Foreign Function Interface) - 50% 4.9. Borrow 와 AsRef 4.11. 배포 채널 (Release Channels) - 100% 5. 문법과 의미 (Syntax and Semantics) - 100% 5.1. 변수 바인딩 (Variable Bindings) - 100% 5.2. 함수 (Functions) - 100% 5.3. 기본형 (Primitive Types) - 100% 5.4. 주석 (Comments) - 100% 5.5. 조건식 (if) - 100% 5.6. 반복 (Loops) - 100% 5.7. 소유권 (Ownership) - 100% 5.8. 참조와 빌림 (References and Borrowing) - 100% 5.9. 수명 (Lifetimes) - 100% 5.10. 가변성 (Mutability) - 100% 5.11. 구조체 (Structs) - 100% 5.12. 열거형 (Enums) - 100% 5.13. 정합 (Match) - 100% 5.14. 패턴 (Patterns) - 80% 5.15. 메소드 문법 (Method Syntax) - 100% 5.16. 벡터 (Vectors) - 100% 5.17. 문자열(Strings) - 100% 5.18. 제너릭 (Generics) - 100% 5.19. 트레잇 (Traits) - 100% 5.20. 드랍 (Drop) - 100% 5.21. if let - 100% 5.22. 트레잇 객체 (Trait Objects) - 75% 5.23. 클로저 (Closures) - 10% 5.24. 전역 함수 사용법 (Universal Function Call Syntax) - 0% 5.25. 크레이트들과(Crate) 모듈들(Module) - 0% 9. 용어 색인 (Concordance) Show all
    Discussions 5 Pending changes 5 Contributors
    Download Share

    Download

    Working...

    Downloading...

    Downloaded!

    Download more

    Error!

    Your download couldn't be processed. Check for abnormalities and incorrect syntax. We've been notified of the issue.

    Back

    Download PDF Download ePub Download HTML Download Word doc Download text Download source (archive)

    Close
878 Words
4,556 Characters

Share

Collaborators make changes on their own versions, and all changes will be approved before merged into the main version.

Close

Penflip is made by Loren Burton
in Los Angeles, California

Tweet

    About

  • Team
  • Pricing
  • Our Story

    Quick Start

  • Markdown
  • Penflip Basics
  • Working Offline

    Support

  • Help
  • Feedback
  • Terms & Privacy

    Connect

  • Email
  • Twitter