[rust] 4. Understanding Ownership - 1

Jiseok Son·2023년 9월 11일
0
post-thumbnail

📌 "The Rust Programming Language"를 읽고 남긴 기록

1. What is Ownership?

모든 프로그램은 실행 중 자신이 사용하는 메모리를 관리하는 방법을 가져야한다. 실행 중 더이상 필요하지 않은 메모리를 수거하는 가비지 컬레터가 포함된 언어가 있는 반면에, 프로그래머가 명시적으로 메모리를 할당하고 해제해야하는 언어가 있다. Rust는 Ownership system을 도입하여 메모리를 관리한다.

1. Ownership Rule

'Ownership Rule' 원문

  • Rust의 모든 값은 Owner를 가진다.
  • 한번에 하나의 Owner만 존재한다.
  • Owner가 scope를 벗어나면 값은 해제된다.

2. Variable scope

변수가 유효한 범위를 scope라 한다.

{
    let s = String::from("Hello world!"); // s is valid
} // scope now over, and s is no longer valid

3. The String Type

let a = "This is string literal, &str typed";
let mut b = String::from("String instance!");
b.push_str(" append here")
  • a는 스택 메모리에 정적으로 할당된 문자열 리터럴을 가리키는 문자열 슬라이스(&str 타입)이다.
  • b는 힙에 할당된 String 타입의 동적 문자열이다.

4. Memory and Allocation

String 타입의 값은

  • 실행 중 필요한 메모리를 요구
  • 사용이 완료되면 메모리를 해제

rust는 scope를 벗어난 변수의 메모리를 해제한다. 간단한 규칙이지만, 더 복잡한 상황에서는 행동을 예측하기 힘들 수 있다. 몇가지 상황을 통해 동작을 살펴보자.

5. Variables and Data Interacting with Move

이미지 출처: https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html#variables-and-data-interacting-with-move

let s1 = String::from("hello");
let s2 = s1;

rust의 String은 content를 가리키는 포인터, 문자열의 길이, 용량 세부분으로 구성되고 스택에 저장된다. 힙 메모리에는 문자열의 content가 저장된다.
s2에 s1을 대입하면, rust는 s1이 더이상 유효하지 않다고 여겨 s1을 통해 값에 접근하는 것을 허용하지 않는다. 이는 실제 값에 접근할 수 있는 능력을 다른 변수로 옮긴 것 처럼 보이며, 이러한 동작을 단순 복사와 구별해 move라 한다.

s1값이 s2로 move되었으므로 s1은 더이상 사용할 수 없으며, 따라서 다음과 같은 구현은 불가능하다.

let s1 = String::from("Hello");
let s2 = s1;

println!("{}", s1); // WRONG!!

6. Variables and Data Interacting with Clone

clone메소드를 이용해 힙에 저장된 String data를 deeply copy할 수 있다.

이미지 출처: https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html#variables-and-data-interacting-with-move

let s1 = String::from("Hello);
let s2 = s1.clone();
println!("{}, {}", s1, s2);

7. Stack only data: Copy

i32와 같이 값이 스택에 저장되는 타입에 지정할 수 있는 Copy라는 특별한 trait이 있다. 값이 스택에 저장되고, 복사를 하면 값이 스택으로 그대로 복사된다(move 하지 않음).

8. Ownership and Functions

함수 호출로 값을 전달하면 ownership이 호출한 함수의 인자로 옮겨진다. 따라서 함수 호출 이후에는 변수를 다시 사용할 수 없다.

fn main() {
    let s = String::from("Hello world");
    take_ownership(s);
    println!("{}", s); // WRONG!!
}

fn take_ownership(s: String) {
    println!("{}", s);
}

9. Return Values and Scope

함수의 반환값을 받아 원래의 ownership을 되찾을 수 있다.

fn main() {
    let s1 = String::from("Hello world);
    let s2 = takes_and_gives_back(s1);
    println!("{}", s2); // OK
}

fn takes_and_gives_back(s: String) -> String {
    s
}
profile
make it work make it right make it fast

0개의 댓글