<p style="text-align:justify;">Rust. 최근 레딧(Reddit)이나 해커뉴스(HackerNews)를 보면 아주 빈번하게 접할 수 있는 프로그래밍 언어입니다.</p><p style="text-align:justify;"> </p><p style="text-align:justify;">이 언어는 C++을 대체할 수 있는 언어로 유명한데요. C++의 오랜 사용자 입장에서 Rust가 과연 어떤 메커니즘으로 C++을 대체하고자 하는지 알아두면 좋은 시점이라고 생각했습니다.</p><p style="text-align:justify;"> </p><p style="text-align:justify;">과연 Rust는 어떤 특징이 있길래, 이렇게 인기를 얻고 있는 걸까요?</p><div class="page-break" style="page-break-after:always;"><span style="display:none;"> </span></div><h3 style="text-align:justify;"><strong>Rust! 어떤 언어인지 아시나요?</strong></h3><h4 style="text-align:justify;"><strong>Rust는 누가 만들었을까?</strong></h4><p style="text-align:justify;">Rust는 지난 2010년, 모질라 재단의 후원으로 개발된 프로그래밍 언어입니다. 모질라 재단은 파이어폭스와 썬더버드 같은 유명한 오픈 소스 프로젝트로 잘 알려져 있습니다. 초기 개발자는 그레이던 호어(Graydon Hoare)로 모질라에서 근무하며 Rust의 기본 아이디어를 구상하고 구현하기 시작했다고 합니다. 호어의 개인 프로젝트였던 Rust는 곧 모질라 재단의 공식적인 지원을 받게 되었고, 2020년 Rust 재단이 설립되며 언어 개발과 생태계가 더욱 활발해졌습니다.</p><p style="text-align:justify;"> </p><p style="text-align:justify;">이러한 Rust는 시스템 프로그래밍 언어로, 특히 C와 C++의 단점을 보완하고자 하는 목적에서 탄생했습니다. 더 나은 안정성과 성능, 특히 병렬 처리의 안전성을 핵심 목표로 개발되었죠.</p><p style="text-align:justify;"> </p><h4 style="text-align:justify;"><strong>Rust의 5가지 특징을 알아봅시다</strong></h4><p style="text-align:justify;">Rust의 주요 특징은 이렇습니다.</p><p style="text-align:justify;"> </p><ul><li style="text-align:justify;"><strong>높은 메모리 안전성</strong>: 컴파일 시점에서 메모리 접근 오류를 방지함으로써 런타임에 발생할 수 있는 여러 오류를 사전에 차단합니다.</li><li style="text-align:justify;"><strong>뛰어난 성능</strong>: C, C++과 유사한 수준의 고성능을 제공합니다.</li><li style="text-align:justify;"><strong>병렬 처리의 안전성</strong>: 데이터 경합을 방지하고 안전한 병렬 처리를 지원합니다.</li><li style="text-align:justify;"><strong>고유 소유권 시스템</strong>: 고유한 소유권 시스템인 ‘빌림 검사기(Borrow Checker)’ 도입으로 메모리 관리의 효율성을 극대화합니다.</li><li style="text-align:justify;"><strong>풍부한 타입 시스템과 패턴 매칭</strong>: 다양한 타입 시스템과 패턴 매칭을 적용해 코드의 안전성과 가독성을 높이는 데 기여합니다.</li></ul><p style="text-align:justify;"> </p><h4 style="text-align:justify;"><strong>어째서 실리콘 밸리에선 이렇게 핫할까요?</strong></h4><p style="text-align:justify;">Rust는 실리콘 밸리의 주요 기업들로부터 관심을 받고 있습니다. 나사, 마이크로소프트, 리눅스 커뮤니티, 안드로이드 프로젝트 등 여러 곳에서 개발 언어로 Rust를 선택하고 있죠. 특히 새로 도입할 기술을 결정하는 관점이 아닌 기존 C++ 코드를 재작성 하는 선택지로 많이 쓰이고 있습니다. (<a href="https://thenextweb.com/news/why-rust-developers-favourite-programming-language">참고 글</a>)</p><p style="text-align:justify;"> </p><p style="text-align:justify;">여러 가지 Rust의 특징 중에서도 아래 특징이 큰 영향을 주었을 겁니다.</p><p style="text-align:justify;"> </p><ul><li style="text-align:justify;"><strong>안정성</strong>: 메모리 안전성과 병렬 처리 안전성을 보장하여 소프트웨어의 안정성을 높일 수 있습니다.</li><li style="text-align:justify;"><strong>성능</strong>: 시스템 프로그래밍 언어로서 C++와 동등한 성능을 제공하면서도, 더 나은 메모리 관리 기능을 갖추고 있습니다.</li><li style="text-align:justify;"><strong>생산성</strong>: Rust의 강제된 메모리 관리 규칙과 문법, 또한 실수의 여지를 줄이는 규칙은 초기 학습 비용이 크지만, 이에 적응한 개발자들의 생산성과 안정성을 올려줍니다.</li></ul><p style="text-align:justify;"> </p><p style="text-align:justify;"> </p><h3 style="text-align:justify;"><strong>C++ vs. Rust. 그래서 무엇이 다른가요?</strong></h3><h4 style="text-align:justify;"><strong>하나하나 짚어보며 차이점을 알아볼까요?</strong></h4><p style="text-align:justify;"> </p><p style="text-align:justify;"><strong>1. 메모리 안전성</strong></p><ul><li style="text-align:justify;"><strong>C와 C++:</strong> C와 C++은 수동 메모리 관리를 요구합니다. 따라서 개발자가 직접 메모리를 할당하고 해제해야 하는데요. 그 때문에 메모리 누수, 잘못된 메모리 접근(예: 댕글링 포인터, 버퍼 오버플로우) 같은 문제가 발생하기 쉽습니다.</li></ul><p style="text-align:justify;"> </p><ul><li style="text-align:justify;"><strong>Rust:</strong> Rust는 고유한 소유권 시스템 ‘빌림 검사기(Borrow Checker)’를 적용해 메모리를 자동으로 관리합니다. 이 시스템은 컴파일 타임에 메모리 안전성을 보장하고, 댕글링 포인터나 버퍼 오버플로우 같은 메모리 접근 관련 문제를 방지합니다. 또한 생명주기(Lifetime) 시스템에서 참조가 유효한 기간을 명시적으로 관리하며 메모리 안전성을 강화합니다.</li></ul><p style="text-align:justify;"> </p><p style="text-align:justify;"><strong>2. 병렬 처리의 안전성</strong></p><ul><li style="text-align:justify;"><strong>C와 C++:</strong> 이 언어를 쓰면 병렬 처리를 구현할 때 <strong>데이터 경합 조건(race condition)</strong>을 방지하기 어렵습니다. 무엇보다 개발자가 직접 동기화 메커니즘을 사용해야 하는데, 잘못된 동기화는 치명적인 버그를 초래할 수 있습니다.</li></ul><p style="text-align:justify;"> </p><ul><li style="text-align:justify;"><strong>Rust:</strong> Rust 표준 라이브러리에서 제공하는 <strong>Send와 Sync 트레잇</strong>으로 안전한 병렬 처리를 지원합니다. 이 트레잇들은 타입 시스템에 의해 강제되며, 데이터 경합 조건을 컴파일 타임에 방지합니다. 또한 <strong>안전한 병렬 처리(fearless concurrency)</strong>를 장려하며, 데이터 경합 없이 병렬 코드를 작성할 수 있도록 설계되었습니다.</li></ul><p style="text-align:justify;"> </p><p style="text-align:justify;"><strong>3. 에러 처리</strong></p><ul><li style="text-align:justify;"><strong>C와 C++:</strong> C는 기본적으로 <strong>예외 처리</strong>를 지원하지 않습니다. 그래도 C++는 예외 처리 메커니즘을 제공하지만, 잘못 사용하면 프로그램의 안정성을 해칠 수 있습니다.</li></ul><p style="text-align:justify;"> </p><ul><li style="text-align:justify;"><strong>Rust:</strong> Rust는 <strong>Result와 Option이라는 타입</strong>으로 명시적인 에러 처리를 강제합니다. 이 타입들을 사용하면 함수가 성공하거나 실패할 때의 결과를 명확하게 표현할 수 있으며, 에러 처리를 강제하여 안전한 코드를 작성할 수 있습니다. 또한 Rust는 비정상 종료가 필요할 때 <strong>panic! 매크로</strong>를 사용해 명시적으로 프로그램을 중단시킵니다. 이로써 예외 처리를 명확하게 하고, 예상치 못한 오류를 방지할 수 있죠.</li></ul><p style="text-align:justify;"> </p><p style="text-align:justify;"><strong>4. 현대적 문법과 생산성</strong></p><ul><li style="text-align:justify;"><strong>C와 C++:</strong> C와 C++는 오래된 언어입니다. 따라서 현대적인 개발 패턴을 적용하기 어렵고, <strong>문법은 복잡</strong>하며, 코드 유지보수가 어렵습니다.</li></ul><p style="text-align:justify;"> </p><ul><li style="text-align:justify;"><strong>Rust:</strong> Rust는 최근에 만들어진 프로그래밍 언어인 만큼, <strong>모던한 문법</strong>을 채택해 코드의 가독성과 유지보수성을 높였습니다. 매크로 시스템, 패턴 매칭, 그리고 강력한 타입 시스템이 대표적인 예시입니다. 여기에 <strong>Cargo라는 빌드 및 패키지 관리 도구</strong>로 라이브러리 의존성을 쉽게 관리하고, 빌드 과정을 단순화합니다.</li></ul><p style="text-align:justify;"> </p><p style="text-align:justify;"><strong>5. 성능</strong></p><ul><li style="text-align:justify;"><strong>C와 C++:</strong> C와 C++는 <strong>낮은 수준의 제어</strong>를 지원합니다. 이러한 제어는 버그와 안전성 문제를 유발할 수 있습니다.</li></ul><p style="text-align:justify;"> </p><ul><li style="text-align:justify;"><strong>Rust:</strong> Rust는 고성능을 유지하면서도 안전한 추상화를 제공합니다. 이러한 <strong>제로 비용 추상화 원칙</strong>으로 런타임 오버헤드 없이 안전한 코드를 작성할 수 있습니다.</li></ul><p style="text-align:justify;"> </p><h4 style="text-align:justify;"><strong>예시 코드로 Rust의 특징을 자세히 알아봅시다</strong></h4><p style="text-align:justify;"><strong>1. 동적 메모리 관리</strong></p><p style="text-align:justify;">메모리를 동적으로 관리하는 것은 현대 언어에서는 소수 언어만 가진 특징입니다. 메모리를 잘 관리하면 고성능 애플리케이션을 만들 수 있습니다. 대신 실수의 여지가 있죠.</p><p style="text-align:justify;"> </p><p style="text-align:justify;">수동으로 메모리 할당 해제를 해야 하는 것은 C++ 문법의 단점입니다. 물론 C++의 경우에도 스마트 포인터를 쓰면 보강되긴 하지만, 강제된 규칙은 아닙니다. 따라서 C++의 표준적인 메모리 관리 규칙에서는 엄연한 단점이라고 볼 수 있습니다.</p><p style="text-align:justify;"> </p><figure class="image image_resized" style="width:100%;"><img src="https://yozm.wishket.com/media/news/2635/image1.png"><figcaption>C++ 코드 <출처: 작가></figcaption></figure><p style="text-align:justify;"> </p><p style="text-align:justify;">여기서 delete 키워드를 활용한 메모리 해제 부분을 누락한다면, 메모리 누수가 발생하게 됩니다.</p><p style="text-align:justify;"> </p><figure class="image image_resized" style="width:100%;"><img src="https://yozm.wishket.com/media/news/2635/image7.png"><figcaption>Rust 코드 <출처: 작가></figcaption></figure><p style="text-align:justify;"> </p><p style="text-align:justify;">예시 코드에서 my_object는 use_my_class 함수 끝에서 자동으로 소멸하며 메모리가 해제됩니다. <strong>이처럼 Rust의 소유권 시스템은 자동으로 메모리를 관리합니다.</strong>사실 이러한 규칙은 C++의 스마트 포인터, 그리고 자바 등 레퍼런스 카운팅 기반의 Garbage Collection으로 잘 구현되어 있습니다. 색다를 것 없다고 느낄 수도 있겠죠.</p><p style="text-align:justify;"> </p><p style="text-align:justify;">그러나 차이가 없다면, Rust가 지금보다 주목을 덜 받았을 겁니다. Rust의 소유권 시스템에 대해 더 자세히 알아봅시다.</p><p style="text-align:justify;"> </p><p style="text-align:justify;"><strong>2. 생명 주기와 소유권 시스템</strong></p><p style="text-align:justify;">C++에서는 개발자가 직접 메모리를 관리해야 합니다. 따라서 메모리 해제를 잊어버리는 경우, 메모리 누수가 발생할 수 있습니다. 또한, 동일한 메모리를 여러 포인터가 참조할 때 발생할 수 있는 댕글링 포인터(Dangling Pointer, 주인 잃은 포인터) 문제도 존재합니다.</p><p style="text-align:justify;"> </p><p style="text-align:justify;">Rust는 소유권 시스템을 통해 이러한 문제를 방지합니다. 여기서 <strong>소유권(Ownership)</strong>이란, 각 값은 오직 하나의 소유자만 가질 수 있으며, 소유자가 범위를 벗어나면 값은 자동으로 해제된다는 것을 뜻합니다.</p><p style="text-align:justify;"> </p><p style="text-align:justify;">이러한 시스템은 빌림과 생명주기로 구현되죠.</p><p style="text-align:justify;"> </p><ul><li style="text-align:justify;"><strong>빌림(Borrowing)</strong>: 값을 참조할 때는 불변 참조(&T)와 가변 참조(&mut T)를 사용합니다.</li><li style="text-align:justify;"><strong>생명주기(Lifetime)</strong>: 참조의 유효 기간을 컴파일 타임에 검사하여 안전성을 보장합니다.</li></ul><p style="text-align:justify;"> </p><figure class="image image_resized" style="width:100%;"><img src="https://yozm.wishket.com/media/news/2635/image4.png"><figcaption>C++ 코드 <출처: 작가></figcaption></figure><figure class="image image_resized" style="width:100%;"><img src="https://yozm.wishket.com/media/news/2635/image2.png"><figcaption>Rust 코드 <출처: 작가></figcaption></figure><p style="text-align:justify;"> </p><p style="text-align:justify;">C++에서는 참조를 통해 빌림을 구현하지만, Rust에서는 불변 참조(&T)로 빌림을 구현하고 소유권을 옮기지 않습니다. 무엇보다 이러한 Rust의 소유권 시스템과 생명주기 규칙은 컴파일 타임에 참조의 유효성을 검사하여 안전성을 보장합니다.</p><p style="text-align:justify;"> </p><p style="text-align:justify;"><strong>3. 데이터 경합(Race) 방지</strong></p><p style="text-align:justify;">Rust의 소유권 시스템과 생명주기 개념은 병렬 처리와 안정성에서 많은 장점을 제공합니다. 특히, Rust의 타입 시스템과 빌림 검사기(Borrow Checker)는 데이터 경합을 방지함으로써 안전한 병렬 프로그래밍을 지원하죠.</p><p style="text-align:justify;"> </p><p style="text-align:justify;">데이터 경합이란 여러 스레드가 동시에 같은 데이터를 수정하려 할 때 발생하는 문제입니다. 이런 데이터 경합이 발생하면 예상치 못한 결과나 프로그램 오류가 발생할 수 있습니다. Rust는 컴파일 타임에 데이터 경합을 방지하는 메커니즘을 제공합니다. 이로써 높은 성능과 안정성을 동시에 추구할 수 있습니다.</p><p style="text-align:justify;"> </p><figure class="image image_resized" style="width:100%;"><img src="https://yozm.wishket.com/media/news/2635/image3.png"><figcaption>Rust 코드 <출처: 작가></figcaption></figure><p style="text-align:justify;"> </p><p style="text-align:justify;">코드 상단의 Arc, Mutex가 보이시나요? <strong>Arc(</strong>Atomic Reference Counting) 개념은 여러 스레드 간에 소유권을 안전하게 공유할 수 있게 합니다. 또한 <strong>Mutex</strong>는 상호 배제로 여러 스레드가 동시에 데이터에 접근하지 못하도록 합니다.</p><p style="text-align:justify;"> </p><p style="text-align:justify;">이처럼 Rust의 타입 시스템은 Arc와 Mutex를 사용하여 데이터 경합을 방지합니다. Arc는 안전하게 참조를 공유하고, Mutex는 데이터 접근을 동기화하여 경합을 방지합니다.</p><p style="text-align:justify;"> </p><p style="text-align:justify;"><strong>4. 소유권과 빌림 시스템의 안전성</strong></p><p style="text-align:justify;">Rust의 소유권과 빌림 시스템은 데이터 경합을 방지할 뿐만 아니라, 컴파일 타임에 데이터 접근의 안전성을 보장합니다. 이는 런타임에 발생할 수 있는 많은 오류를 사전에 방지합니다.</p><p style="text-align:justify;"> </p><p style="text-align:justify;">특히 Rust의 빌림 규칙은 불변 참조(&T)와 가변 참조(&mut T)를 명확하게 구분합니다. 이러한 규칙으로 데이터의 일관성을 유지하고, 데이터 경합을 방지합니다.</p><p style="text-align:justify;"> </p><p style="text-align:justify;">Rust에서 불변 참조와 가변 참조는 동시에 존재할 수 없습니다. 이는 데이터의 일관성을 유지하고 안전한 동시성을 보장합니다. 컴파일러 역시 이러한 규칙을 강제하여, 불변 참조와 가변 참조가 동시에 존재하지 않도록 합니다.</p><p style="text-align:justify;"> </p><figure class="image image_resized" style="width:100%;"><img src="https://yozm.wishket.com/media/news/2635/image6.png"><figcaption>Rust 코드 <출처: 작가></figcaption></figure><p style="text-align:justify;"> </p><p style="text-align:justify;"><strong>5. Send와 Sync 트레잇</strong></p><p style="text-align:justify;">Rust의 Send와 Sync 트레잇은 병렬 프로그래밍에서 안전성을 보장하는 중요한 역할을 합니다. 만약 타입이 <strong>Send 트레잇</strong>을 구현하면, 해당 타입의 값이 다른 스레드로 안전하게 이동할 수 있음을 의미합니다. 반면 <strong>Sync 트레잇</strong>을 구현하면, 해당 타입의 값이 여러 스레드에서 동시에 접근할 수 있죠.</p><p style="text-align:justify;"> </p><figure class="image image_resized" style="width:100%;"><img src="https://yozm.wishket.com/media/news/2635/image5.png"><figcaption>Rust 코드 <출처: 작가></figcaption></figure><p style="text-align:justify;"> </p><p style="text-align:justify;">위 코드에서 vec![1, 2, 3]은 Send 트레잇을 구현하므로 스레드 사이를 안전하게 이동할 수 있습니다. 또한 Rust 컴파일러는 Send와 Sync 트레잇으로 스레드 간 데이터 이동과 공유의 안전성을 검사합니다.</p><p style="text-align:justify;"> </p><p style="text-align:justify;"><strong>6. 안전한 병렬 처리</strong></p><p style="text-align:justify;">Rust는 여러 도구와 패턴을 제공해 <strong>안전한 병렬 처리(Fearless Concurrency)</strong>를 실현합니다. 이렇게 개발자가 데이터 경합이나 동시성 버그를 두려워하지 않고, 병렬 코드를 작성할 수 있도록 도와줍니다. Arc, Mutex, RwLock 등이 병렬 프로그래밍에서 <strong>데이터의 안전한 공유</strong>를 가능하게 해주며, 채널(Channel)이 스레드 사이 통신을 안전하게 처리할 수 있도록 지원합니다.</p><p style="text-align:justify;"> </p><p style="text-align:justify;"> </p><h3 style="text-align:justify;"><strong>Rust를 지금 배워도 될까요?</strong></h3><h4 style="text-align:justify;"><strong>Rust는 배우기 쉬운가요?</strong></h4><p style="text-align:justify;">Rust는 배우기 쉬운 언어는 아닙니다. 그러나 Rust를 익힌 사람이 많아졌고, 점점 더 늘어나고 있는 걸 보았을 때, 시간을 충분히 들이면 학습할 수 있겠죠. 특히 독특한 소유권 시스템과 생명 주기 규칙이 처음에는 이해하기 어려울 수 있습니다. 그러나 그만큼 개념을 익혔을 때, 안전하고 효율적인 코드를 작성하는 데 큰 도움이 됩니다.</p><p style="text-align:justify;"> </p><h4 style="text-align:justify;"><strong>앞으로도 Rust의 인기가 더 높아질까요?</strong></h4><p style="text-align:justify;">앞서 보았듯 Rust는 이미 개발자들 사이에서 인기를 얻고 있습니다. 그 인기는 계속 높아질 것으로 보입니다. 안정성과 성능, 병렬 처리 특화 덕분에 다양한 산업 분야에서 Rust를 채택하고 있기 때문이죠.</p><p style="text-align:justify;"> </p><p style="text-align:justify;">Rust 재단의 적극적인 지원과 활발한 커뮤니티 활동, 여러 빅테크 기업과 제품에서 사용하는 추세 역시 이를 뒷받침합니다. C++을 여전히 많이 사용하는 마이크로소프트를 비롯해서 메타, 나사 등이 Rust를 다양한 로우 레벨 구현 언어로 채택하고 있죠. (<a href="https://www.theregister.com/2024/01/31/microsoft_seeks_rust_developers/">참고 글</a>)</p><p style="text-align:justify;"> </p><h4 style="text-align:justify;"><strong>한국에서는 대세로 보기 어렵습니다</strong></h4><p style="text-align:justify;">그러나 한국에서는 아직 Rust를 대중적으로 널리 쓰고 있지 않습니다. 여전히 Java, JavaScript, Python 등이 주류로 Rust를 채택한 사례는 상대적으로 매우 적습니다. 로우 레벨의 SDK 등을 만드는 기업들도 대부분 Rust보다는 C++을 사용하는 편이고요. 그러니 한국에서 Rust를 배운다 해도 이직에 직접적인 도움이 되기는 어렵다고 생각합니다.</p><p style="text-align:justify;"> </p><h4 style="text-align:justify;"><strong>하지만 배워 둔다면 다양한 이득을 얻을 수 있습니다</strong></h4><p style="text-align:justify;">Rust는 시스템 프로그래밍, 웹 개발, 임베디드 시스템 등 다양한 분야에서 유용하게 사용될 수 있는 언어입니다. 메모리 안전성과 병렬 처리 안전성이 애플리케이션에 있어 아주 중요한 요소이기 때문이기도 하죠.</p><p style="text-align:justify;"> </p><p style="text-align:justify;">하지만 웹 개발에서 강점도 있다는 점을 모르시는 분들이 많은데요. Rust는 마찬가지로 <a href="https://github.com/flosse/rust-web-framework-comparison">다양한 웹 프레임워크</a>를 가지고 있습니다. Rust를 배우다 보면 병렬 처리에 대한 인사이트, 성능 이슈를 해결할 추가적인 선택지, 안정적인 애플리케이션을 만드는 또다른 방법 등을 익힐 수 있습니다. 또한 클라우드 서비스가 은근슬쩍 자꾸만 비싸지는 이 시점에 유의미한 금전적 의미도 있습니다. 서비스의 트래픽이 늘어날수록 성능 이슈를 해결하는 것만으로 큰 비용을 아낄 수 있으니까요.</p><p style="text-align:justify;"> </p><p style="text-align:justify;"> </p><h3 style="text-align:justify;"><strong>마치며</strong></h3><p style="text-align:justify;">정리해 보겠습니다. Rust는 뛰어난 안정성과 높은 성능, 안전한 병렬 처리를 제공하는 현대적인 시스템 프로그래밍 언어입니다. 실리콘 밸리 주요 기업들로부터 큰 관심을 받고 있으며 앞으로도 인기가 계속 증가할 것으로 예상됩니다. 물론 한국에서는 아직 대중적으로 널리 사용되지 않지만, Rust를 배워둔다면 다양한 분야에서 경쟁력을 갖출 수 있다고 보입니다.</p><p style="text-align:justify;"> </p><p style="text-align:justify;">무엇보다 이 언어는 충분히 성숙한 언어입니다. 특히 Rust를 배우는 과정에서 병렬 처리와 안정적인 메모리 관리를 이해할 수 있다면, 여러분도 특별한 개발자로 성장할 수 있을 겁니다.</p><p style="text-align:justify;"> </p><p style="margin-left:0px;text-align:center;"><span style="color:rgb(153,153,153);">요즘IT의 모든 콘텐츠는 저작권법의 보호를 받는 바, 무단 전재와 복사, 배포 등을 금합니다.</span></p>