레이블이 rust인 게시물을 표시합니다. 모든 게시물 표시
레이블이 rust인 게시물을 표시합니다. 모든 게시물 표시

2024년 12월 31일 화요일

rust : lifetime

Rust 라이프타임(Lifetime) 쉽게 이해하기

Rust 라이프타임(Lifetime) 쉽게 이해하기

Rust에서 라이프타임(Lifetime)이란, “참조가 실제로 유효한 기간”을 의미합니다. 이 개념이 있는 이유는, Rust가 메모리 안전성을 보장하기 위해서에요. “값이 살아있는 동안만, 그 값을 참조할 수 있다”는 조건을 엄격하게 지키기 위해서는, “참조가 언제까지 유효한가?”를 Rust 컴파일러가 추적할 수 있어야 합니다.

라이프타임 없이 생기는 혼란

간단한 함수나 로직에서는 라이프타임 표기를 자주 쓰지 않아도 됩니다. 하지만 여러 개의 참조를 인자로 받고, 그 중 하나를 반환하는 함수는 이야기가 달라져요.

fn longest(x: &str, y: &str) -> &str {
    if x.len() > y.len() {
        x
    } else {
        y
    }
}

이 함수가 최종적으로 내보내는 참조가 언제까지 살아 있을지를 컴파일러는 명확히 알 수 없습니다. 특히 xy의 라이프타임(“참조가 유효한 기간”)이 서로 다르거나, 함수 호출 이후에 어떤 식으로 사용되는지에 따라 달라지면 컴파일러로서는 “어느 쪽 라이프타임에 맞춰야 하지?”라는 문제가 생기거든요.

좀 더 구체적으로 왜 혼란이 생길까?

  1. 컴파일러의 역할
    Rust 컴파일러는 참조가 유효한지(= 값이 아직 안 죽었는지) 항상 검사해야 해요. 값(owners)과 빌려 쓰는 참조(borrowers)가 있는데, 빌려 쓰는 동안 원본 값이 사라져버리면 안 되니까요.
  2. 함수 반환 시, 참조의 라이프타임 판단
    우리가 x 또는 y 중 하나를 반환한다고 했을 때, 컴파일러 입장에서는 “반환된 참조는 x의 라이프타임에 따라야 하나, y의 라이프타임에 따라야 하나?”라고 고민을 해야 해요.
    • 만약 x의 라이프타임이 y보다 짧은데 함수가 y를 반환한다면?
    • 그 반대 상황이라면?
    이처럼 어느 한 쪽으로도 결정하기 애매해서, 컴파일러는 에러를 낼 수밖에 없습니다.

명시적 라이프타임으로 해결

그래서 우리가 직접 함수 선언에 <'a>를 붙이고, 파라미터와 반환값에 'a를 지정해 주면 문제가 해결돼요.

fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() {
        x
    } else {
        y
    }
}

이렇게 “둘 다 'a라는 동일한 기간(또는 그 이하)만큼만 유효해!”라고 컴파일러에게 확실히 알려주면, 컴파일러 입장에서는 “어떤 값을 반환하든, 'a라는 라이프타임 범위 내에서만 참조가 사용되는구나!” 하고 안심할 수 있게 됩니다. 결과적으로 컴파일러가 “라이프타임이 모호하다”는 이유로 에러를 내지 않는 것이죠.

정리하자면

  • 라이프타임은 참조(예: &str)가 언제까지 유효한가를 나타내는 개념입니다.
  • 함수 반환 시 여러 참조 중 어느 것을 반환하는 로직이 들어가면, 컴파일러가 정확한 라이프타임을 추론하기 어려워집니다.
  • 명시적 라이프타임(<'a>)을 써서 “함수의 파라미터와 반환값 사이의 라이프타임 관계”를 직접 명시해 주면, 컴파일러가 모호함 없이 판단할 수 있습니다.
  • 결국 무효 참조(Dangling Pointer)를 방지하고, Rust가 메모리 안전성을 컴파일 타임에 보장하도록 돕는 핵심 장치가 라이프타임이에요.

라이프타임은 Rust가 제공하는 강력한 메모리 안전 장치이지만, 처음에는 생소해서 어렵게 느껴질 수 있어요. 그래도 위 예시처럼 “왜 필요한지, 컴파일러가 어떤 혼란을 느끼는지”를 이해하면, 보다 쉽게 다가갈 수 있을 것입니다!

2017년 6월 22일 목요일

In Why Rust


Writing Chat in Rust라는 글에서,

http://nbaksalyar.github.io/2015/07/10/writing-chat-in-rust.html
But arguably the most common pitfall is the memory safety. It is the root cause for a class of bugs such as buffer overflowsmemory leaksdouble deallocations, and dangling pointers. And these bugs can be really nasty: well known issues like the infamous OpenSSL Heartbleed bug is caused by nothing more than the incorrect management of memory — and nobody knows how much more of these severe bugs are lurking around.
However, there are several good practice approaches in C++ such as smart pointers[1] and on-stack allocation[2] to mitigate these common issues. But, unfortunately, it’s still too easy to “shoot yourself in the foot” by overflowing a buffer or by incorrectly using one of the low-level memory management functions because these practices and constraints aren’t enforced on the language level.
Instead, it’s believed that all well-grounded developers would do good and make no mistakes whatsoever. Conversely, I do believe that these critical issues have nothing to do with the level of skill of a developer because it’s a machine’s task to check for errors — human beings just don’t have that much attention to find all weaknesses in large codebases.
That’s the major reason of existence for a common way to automatically handle the memory management: the garbage collection. It’s a complex topic and a vast field of knowledge in itself. Almost all modern languages and VMs use some form of GC, and while it’s suitable in most cases, it has its own shortcomings — it’s complex[3], it introduces an overhead of a pause to reclaim unused memory[4], and generally requires intricate tuning tricks for high-performance applications to reduce the pause time.


인간이 방대한 코드베이스의 모든 약점을 찾는데 주의를 기울여야 한다고 생각하지 않는다.

21세기적인 프로그래머 마인드라서 마음에 든다. ^^

그리고, GC가 대부분의 경우 적합하지만 한계가 있다는 것을 알아야 한다.

Rust takes a slightly different approach — basically, a middle ground: automatic memory and resources reclamation without a significant overhead and without the requirement of a tiresome and error-prone manual memory management. It’s achieved by employing ownership and borrowing concepts.

그래서, Rust 가 채용한 방식은 수동과 자동을 섞은 것이다.
ownership 개념과 borrowing 개념을 도입한 것이다.

http://nbaksalyar.github.io/2015/07/10/writing-chat-in-rust.html

rust를 학습하고자 한다면, 지루하게 rust by example을 보는 것보다, 요 링크를 먼저 한번 쭉 읽어보시길 권한다.  rust를 배우고자 하는 동기부여도 될 것이고, rust에 대한 전반적인 이해가 될 것이다.