[Rust] Reference life-time (<'a>)

iguigu·2022년 5월 5일
1

Introduction

  • Rust는 다른언어들과 다르게 reference의 lifetime에 대해 컴파일 타임에 체크함
  • lifetime이 모호한 경우 컴파일에러가 발생하며, 이를 방지하기 위해 lifetime parameter를 사용함
  • 기본적으로 모든 reference는 life-time을 가지고 있음
  • 그렇지만 기본적으로 컴파일러는 이를 생략할 수 있도록 허용함
fn bar<'a>(...)
  • 함수는 generic parameter를 <> 사이에 가질 수 있으며 life-time이 그 중 한 케이스임
  • <>는 lifetime을 선언하는 데 사용되며 bar는 하나의 lifetime을 가짐('a)

Borrow checker

let p;

{
    let num = 10;
    p = &num;
}

println!("{}",p);
  • 위의 코드는 컴파일 에러를 발생시킴. 이는 p가 num의 레퍼런스인데 println이 호출되는 시점에 num의 lifetime이 만료되어 p가 dangling reference가 되기 때문임.
  • C의 경우에는 컴파일 에러가 발생하지 않지만 Rust는 Borrow checker가 이를 확인함
fn longest(x: &str, y: &str) -> &str {
    if x.len() > y.len() {
        x
    } else {
        y
    }
}

 --> src\main.rs:5:33
  |
5 | fn longest(x: &str, y: &str) -> &str {
  |                                 ^ expected lifetime parameter
  |
  = help: this function's return type contains a borrowed value, 
  but the signature does not say whether it is borrowed from `x` or `y`
  • 위의 예시의 경우 리턴 값이 x일지 y일지 알수 없어서 에러를 발생 시킴
  • 이를 해결하기 위해선 아래와 같이 lifetime을 명시해주어야 함
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() {
        x
    } else {
        y
    }
}
  • 여기서 a라는 lifetime을 이용하여 두 매개변수의 lifetime을 명시하여 줌
  • 주의할 점은 lifetime parameter가 실제 lifetime에 영향을 주지 않음
  • 단순히 컴파일러에게 x,y 그리고 리턴값이 최소한 a만큼 lifetime을 갖는다는 정보만 제공. 즉 아래와 같은 경우에는 컴파일 에러가 발생함
fn longest<'a>(x: &str, y: &str) -> &'a str {
    let result = String::from("really long string");
    result.as_str()
}

Struct and lifetime

  • Rust는 &strString이 존재하며, &str은 string slice로 고정된 길이를 가지며 변경이 불가능함.
let greeting = "Hello there."; // greeting : &'static str
  • "Hello there."은 string literal이며 타입은 &'static str
  • string literal이란 string sliced로 statically allocated 되기 때문에 컴파일 프로그램 내에 저장되어 실행되는 전체 기간동안 존재함
  • greeting binding은 statically allocated 된 string의 reference임
  • string slice를 받아드리는 함수는 string literal 또한 받을 것임
#[derive(Debug)]
struct Person<'a> {
    name: &'a str,
    age: u8
}

fn main() {
    let name = "Peter";
    let age = 27;
    let peter = Person { name, age };

    // Pretty print
    println!("{:#?}", peter);
}
  • 이 코드는 아래와 같이 수정이 가능함
#[derive(Debug)]
struct Person {    // instead of: struct Person<'a> {
    name: String,  // instead of: name: &'a str 
    age: u8
}

fn main() {
    let name = String::from("Peter");  // instead of: let name = "Peter"; which is &'static str
    let age = 27;
    let peter = Person { name, age };

    // Pretty print
    println!("{:#?}", peter);
}
profile
2929

0개의 댓글