또 다른 Rust 소유권 튜토리얼

발행: (2025년 12월 11일 오후 06:02 GMT+9)
5 min read
원문: Dev.to

Source: Dev.to

Rust에서 가장 중요한 개념 중 하나는 소유권(ownership)빌리기(borrowing) 입니다. 이 주제에만 전념한 글이 수없이 많으며, 이 튜토리얼은 예시를 통해 개념을 설명하려고 합니다.

소유권 은 Rust 프로그램이 메모리를 관리하는 방식을 규정하는 일련의 규칙입니다. Rust는 컴파일 시점에 소유권 시스템을 검사합니다; 규칙이 위반되면 프로그램은 컴파일되지 않으며, 런타임 오버헤드도 없습니다.

What Is Ownership?

소유권의 첫 맛보기

Java 버전

public void own(String text) {}

public static void main(String[] args) {
    var text = "my text";
    own(text);
    System.out.println(text);
}

Rust 번역

fn own(_: String) {}

fn main() {
    let text: String = String::from("my text"); // 1
    own(text);
    println!("{}", text);
}

컴파일러가 불평합니다:

error[E0382]: borrow of moved value: `text`
 --> src/main.rs:11:20
  |
9 |     let text: String = String::from("my text");
  |         ---- move occurs because `text` has type `String`, which does not implement the `Copy` trait
10|     own(text);
  |         ---- value moved here
11|     println!("{}", text);
  |                    ^^^^ value borrowed here after move
...
help: consider cloning the value if the performance cost is acceptable
10|     own(text.clone());

own 함수는 text 의 소유권을 가져가므로, 이후에 text 를 사용할 수 없습니다.

Clone 과 Copy

컴파일러의 조언을 따라 보면:

fn own(text: String) {}

fn main() {
    let text = String::from("my text");
    own(text.clone()); // 깊은 복사
    println!("{}", text);
}

StringClone 을 구현하고 있어 깊은 복사를 수행합니다. 이는 값에 대해 메모리를 두 배로 사용한다는 의미입니다.

타입이 Copy 도 구현한다면, 값이 암시적으로 복제되며 clone() 을 호출할 필요가 없습니다:

#[derive(Debug, Copy, Clone)]
struct Dummy {}

fn own(_: Dummy) {}

fn main() {
    let dummy = Dummy {};
    own(dummy);               // 자동으로 복사됨
    println!("{:?}", dummy); // 여전히 사용 가능
}

Note: 큰 구조체에 Copy 를 구현하면 모든 이동이 복사를 일으키기 때문에 메모리를 많이 차지할 수 있습니다.

참조로 전달하기

값을 전달하면 소유권이 이동합니다. 함수가 값을 빌리도록 하려면 & 로 참조를 전달합니다:

#[derive(Debug)]
struct Dummy {}

fn borrow(_: &Dummy) {}

fn main() {
    let dummy = Dummy {};
    borrow(&dummy);          // 빌림, 이동 아님
    println!("{:?}", dummy); // 여전히 사용 가능
}

참조를 통해 필드 읽기:

#[derive(Debug)]
struct Dummy {
    foo: String,
}

fn borrow(dummy: &Dummy) {
    println!("{:?}", dummy.foo);
}

fn main() {
    let dummy = Dummy { foo: String::from("Foo") };
    borrow(&dummy);
    println!("{:?}", dummy); // Dummy { foo: "Foo" }
}

데이터 변경하기

mut 없이 변경 시도

#[derive(Debug)]
struct Dummy {
    foo: String,
}

fn main() {
    let dummy = Dummy { foo: String::from("Foo") };
    dummy.foo = String::from("Bar"); // error
}

컴파일러 오류:

error[E0594]: cannot assign to `dummy.foo`, as `dummy` is not declared as mutable
 --> src/main.rs:8:5
  |
8 |     dummy.foo = String::from("Bar");
  |     ^^^^^^^^^ cannot assign
  |
help: consider changing this to be mutable
7 |     let mut dummy = Dummy { foo: String::from("Foo") };

변수를 mutable 로 만들기

#[derive(Debug)]
struct Dummy {
    foo: String,
}

fn main() {
    let mut dummy = Dummy { foo: String::from("Foo") };
    dummy.foo = String::from("Bar");
}

값으로 전달된 매개변수 변경하기

#[derive(Debug)]
struct Dummy {
    foo: String,
}

fn mutate(mut dummy: Dummy) {
    dummy.foo = String::from("Bar");
    println!("{:?}", dummy.foo);
}

fn main() {
    let dummy = Dummy { foo: String::from("Foo") };
    mutate(dummy);
}

가변 참조를 통한 변경

#[derive(Debug)]
struct Dummy {
    foo: String,
}

fn mutate(dummy: &mut Dummy) {
    dummy.foo = String::from("Bar");
    println!("Inside: {:?}", dummy.foo);
}

fn main() {
    let mut dummy = Dummy { foo: String::from("Foo") };
    mutate(&mut dummy);
    println!("Outside: {:?}", dummy.foo);
}

요약

목표달성 방법
소유권 가져오기값으로 전달하기
값 복제하기Clone 구현하고 clone() 호출
값 자동 복제하기Copy 구현 (Clone 포함)
빌리기 (읽기 전용)&T 형태의 참조 전달
로컬 변수 변경하기변수 선언 시 mut 지정
참조를 통한 변경&mut T 사용하고 바인딩을 mut 선언

원본은 A Java Geek에 2025년 12월 7일에 게시되었습니다.

Back to Blog

관련 글

더 보기 »