Rust 생명 주기

mohadang·2023년 1월 21일
0

Rust

목록 보기
10/30
post-thumbnail

명시적 생명주기

struct Foo {
    x: i32,
}

// 어떤 값이 더 큰지 비교하여 큰 값을 반환하기 위해 참조를 받고 참조를 반환 하도록 하였다.
fn max(foo_a: &Foo, foo_b: &Foo) -> &Foo {
    if foo_a.x > foo_b.x {
        return foo_a;
    }
    foo_b
}

fn main() {
    let foo_a = Foo { x: 42 };
    let foo_b = Foo { x: 12 };
    let res = max(&foo_a, &foo_b);
    // 컴파일러 입장에서
    // 더 큰 인스턴스가 반환되고 작은 인스턴스는 여기서 소멸 시켜야 한다.
    // 하지만 컴파일러는 어떤 인스턴스가 반환될지 예측할 수 없고 컴파일 시점에
    // 생명 주기를 계산하지 못한다.
    println!("{}", foo_b.x);
    println!("{}", res.x);
}
 --> src\main.rs:7:37
  |
7 | fn max(foo_a: &Foo, foo_b: &Foo) -> &Foo {
  |               ----         ----     ^ expected named lifetime parameter
  |
help: consider introducing a named lifetime parameter
  |
7 | fn max<'a>(foo_a: &'a Foo, foo_b: &'a Foo) -> &'a Foo {
  |       ++++         ++              ++          ++

이 문제를 해결하기 위해서는 명시적인 생명 주기를 지정 해야한다.

n max<'a>(foo_a: &'a Foo, foo_b: &'a Foo) -> &'a Foo {
    if foo_a.x > foo_b.x {
        return foo_a;
    }
    foo_b
}

fn main() {
    let foo_a = Foo { x: 42 };
    let foo_b = Foo { x: 12 };
    let res = max(&foo_a, &foo_b);
    println!("{}", foo_b.x);
    println!("{}", res.x);
}

'a 로 지정된 인자와 반환값은 생명 주기가 같다는 뜻이다.
결론적으로 수명 문법은 함수의 여러 매개변수와 리턴값의 수명을 연결한다.(정확히는 여러 매개변수중 생명 주기가 가장 짧은 것과 연결 해야한다)

일단 수명이 연결되면 러스트는 메모리에 안정적인 작업을 허용하고, 죽은 포인터나 기타 메모리 안전성을 위반하는 작업을 차단하는 데 필요한 충분한 정보를 얻는다.

fn main() {
    let foo_a = Foo { x: 42 };
    let res;
    {
        let foo_b = Foo { x: 12 };
        res = max(&foo_a, &foo_b);// error
        println!("{}", foo_b.x);
        //foo_b의 생명 주기는 끝났지만 res의 생명 주기는 아직 남아있다.
        //만약 res에 foo_b를 참조 하도록 하였다면 문제가 발생 하였을 것이다.
    }
    println!("{}", res.x);
}

정적인 생명주기

static 변수는 컴파일 타임에 생성되어 프로그램의 시작부터 끝까지 존재.
이들은 명시적으로 자료형을 지정 해주어야 함.
static 생명 주기는 프로그램이 끝날 때까지 무한정 유지되는 메모리 리소스이다. 따라서 'static 이라는 특별한 생명 주기 지정자를 갖는다.
'static한 리소스는 절대 Drop 되지 않는다. 그래서 이 리소스가 실제로 프로그램의 전체 수명과 같아야 하는지 생각해 볼 필요가 있다.
만약 static 생명 주기를 갖는 리소스가 참조를 포함하는 경우, 그들도 모두 'static이어야 한다.

static PI: f64 = 3.1415
fn main() {
	static mut SECRET: &'static str = "swordfish";
    
    let msg: &'static str = "Hello World!";
    let p: &'static f64 = &PI;
}

구조체 생명주기

함수와 마찬가지로 구조체의 멤버도 생명 주기 지정자로 지정 가능하다.
그러려면 구조체 정의에 포함된 모든 참조에 명시적 수명을 지정해야 한다.

// Foo 인스턴스가 i 필드에 저장한 참조의 수명을 벗어날 수 없다.
struct Foo<'a> { 
    i:&'a i32
}
fn main() {
    let x = 42;
    let foo = Foo {
        i: &x
    };
    println!("{}",foo.i);
}

Rust에서 참조의 의미는 반드시 데이터가 유효하다는 의미이다.

아무 것도 아닌 것을 가리키는 참조를 들고 다니는 struct란 있을 수 없다.

profile
mohadang

0개의 댓글