목차
1. [왜 Rust인가](#1-왜-rust인가)
2. [소유권(Ownership)](#2-소유권ownership)
3. [라이프타임](#3-라이프타임)
4. [열거형과 패턴 매칭](#4-열거형과-패턴-매칭)
5. [에러 처리](#5-에러-처리)
6. [구조체와 트레이트](#6-구조체와-트레이트)
7. [비동기 프로그래밍](#7-비동기-프로그래밍)
8. [Cargo 패키지 매니저](#8-cargo-패키지-매니저)
9. [실전 Rust](#9-실전-rust)
10. [Rust in 2026](#10-rust-in-2026)
1. 왜 Rust인가
1.1 C/C++의 문제점
시스템 프로그래밍 분야에서 C와 C++은 수십 년간 지배적인 위치를 차지해 왔습니다. 하지만 이 언어들은 근본적인 문제를 안고 있습니다.
| 문제 유형 | 설명 | 결과 |
| --- | --- | --- |
| 버퍼 오버플로 | 배열 경계를 넘는 접근 | 보안 취약점 |
| 댕글링 포인터 | 해제된 메모리를 참조 | 정의되지 않은 동작 |
| 이중 해제 | 같은 메모리를 두 번 해제 | 크래시 또는 보안 위협 |
| 데이터 레이스 | 동시 접근 시 동기화 부재 | 비결정적 버그 |
| 널 포인터 역참조 | null 값을 역참조 | 프로그램 크래시 |
Microsoft에 따르면, Windows 보안 취약점의 약 70%가 메모리 안전성 문제에서 기인합니다. Google의 Chrome 팀 역시 유사한 수치를 보고했습니다.
1.2 Rust의 해답
Rust는 **컴파일 타임에 메모리 안전성을 보장**하면서도 **가비지 컬렉터(GC) 없이** 동작합니다. 이것이 Rust를 독특하게 만드는 핵심입니다.
- **제로 코스트 추상화**: 런타임 오버헤드 없는 고수준 추상화
- **소유권 시스템**: 컴파일러가 메모리를 추적
- **스레드 안전성**: 데이터 레이스를 컴파일 타임에 방지
- **풍부한 타입 시스템**: 많은 버그를 컴파일 타임에 잡음
1.3 Rust의 인기 상승
Stack Overflow 설문조사에서 Rust는 2016년부터 2025년까지 10년 연속 "가장 사랑받는 언어" 1위를 차지했습니다. 2024~2026년 사이에는 실제 산업 채택률도 크게 증가했습니다.
- **Linux 커널**: Rust를 공식 제2 언어로 채택
- **Android**: 새로운 시스템 컴포넌트에 Rust 사용
- **AWS**: Firecracker, Bottlerocket 등 핵심 인프라에 Rust 활용
- **Microsoft**: Windows 커널 코드를 Rust로 재작성 시작
- **Cloudflare**: 네트워크 프록시를 Rust로 전환
2. 소유권(Ownership)
2.1 소유권의 3가지 규칙
Rust의 핵심 개념인 소유권은 3가지 규칙으로 요약됩니다.
1. Rust의 모든 값은 **소유자(owner)** 가 있다
2. 한 시점에 소유자는 **단 하나**뿐이다
3. 소유자가 스코프를 벗어나면 값은 **자동으로 해제**된다
fn main() {
let s1 = String::from("hello"); // s1이 String의 소유자
let s2 = s1; // 소유권이 s2로 이동(move)
// println!("{}", s1); // 컴파일 에러! s1은 더 이상 유효하지 않음
println!("{}", s2); // OK
} // s2가 스코프를 벗어나면 메모리 해제
2.2 이동(Move)과 복사(Copy)
기본적으로 Rust는 값을 **이동(move)** 합니다. 단, `Copy` 트레이트를 구현한 타입은 복사됩니다.
// 정수형은 Copy 트레이트 구현 - 복사됨
let x = 5;
let y = x;
println!("x = {}, y = {}", x, y); // 둘 다 사용 가능
// String은 Copy 미구현 - 이동됨
let s1 = String::from("hello");
let s2 = s1; // 이동!
// s1은 사용 불가
// 명시적 복사가 필요하면 clone 사용
let s3 = String::from("world");
let s4 = s3.clone();
println!("s3 = {}, s4 = {}", s3, s4); // 둘 다 사용 가능
`Copy`를 구현하는 타입들: 정수(`i32`, `u64` 등), 부동소수점(`f32`, `f64`), 불리언(`bool`), 문자(`char`), 이들로만 구성된 튜플.
2.3 빌림(Borrowing)과 참조
소유권을 넘기지 않고 값을 사용하려면 **참조(reference)** 를 사용합니다.
fn calculate_length(s: &String) -> usize {
s.len()
} // s는 참조이므로 여기서 해제되지 않음
fn main() {
let s1 = String::from("hello");
let len = calculate_length(&s1); // 빌림 (불변 참조)
println!("'{}' 의 길이: {}", s1, len); // s1 여전히 유효
}
2.4 가변 참조와 불변 참조
Rust는 참조에 대해 엄격한 규칙을 적용합니다.
fn main() {
let mut s = String::from("hello");
// 불변 참조는 여러 개 동시에 가능
let r1 = &s;
let r2 = &s;
println!("{} and {}", r1, r2);
// 가변 참조는 하나만 가능
let r3 = &mut s;
r3.push_str(", world");
println!("{}", r3);
// 불변 참조와 가변 참조를 동시에 가질 수 없음
// let r4 = &s;
// let r5 = &mut s; // 컴파일 에러!
}
이 규칙 덕분에 **데이터 레이스가 컴파일 타임에 방지**됩니다.
2.5 슬라이스
슬라이스는 컬렉션의 일부를 참조하는 방법입니다.
fn first_word(s: &str) -> &str {
let bytes = s.as_bytes();
for (i, &item) in bytes.iter().enumerate() {
if item == b' ' {
return &s[0..i];
}
}
&s[..]
}
fn main() {
let s = String::from("hello world");
let word = first_word(&s);
println!("첫 번째 단어: {}", word); // "hello"
}
3. 라이프타임
3.1 라이프타임이 필요한 이유
라이프타임은 참조가 유효한 범위를 나타냅니다. 컴파일러는 참조가 가리키는 데이터보다 오래 살아남지 않도록 보장해야 합니다.
// 이 코드는 컴파일되지 않음 - 댕글링 참조 방지
// fn dangle() -> &String {
// let s = String::from("hello");
// &s // s가 함수 끝에서 해제되므로 참조가 무효
// }
// 올바른 방법: 값을 직접 반환
fn no_dangle() -> String {
let s = String::from("hello");
s // 소유권이 호출자에게 이동
}
3.2 라이프타임 어노테이션
컴파일러가 참조의 유효 기간을 추론할 수 없을 때, 명시적 라이프타임 어노테이션이 필요합니다.
// 두 문자열 슬라이스 중 긴 것을 반환
// 반환값의 라이프타임은 두 인자 중 짧은 쪽을 따름
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() {
x
} else {
y
}
}
fn main() {
let string1 = String::from("long string");
let result;
{
let string2 = String::from("xyz");
result = longest(string1.as_str(), string2.as_str());
println!("더 긴 문자열: {}", result); // 여기서는 OK
}
// println!("{}", result); // string2가 해제되어 에러 가능
}
3.3 구조체의 라이프타임
구조체가 참조를 포함할 때도 라이프타임을 명시해야 합니다.
struct ImportantExcerpt<'a> {
part: &'a str,
}
impl<'a> ImportantExcerpt<'a> {
fn level(&self) -> i32 {
3
}
fn announce_and_return_part(&self, announcement: &str) -> &str {
println!("주목! {}", announcement);
self.part
}
}
fn main() {
let novel = String::from("Call me Ishmael. Some years ago...");
let first_sentence;
{
let i = novel.find('.').unwrap_or(novel.len());
first_sentence = &novel[..i];
}
let excerpt = ImportantExcerpt {
part: first_sentence,
};
println!("인용: {}", excerpt.part);
}
3.4 정적 라이프타임
`'static` 라이프타임은 프로그램 전체 실행 기간 동안 유효한 참조를 의미합니다.
// 문자열 리터럴은 항상 'static
let s: &'static str = "이 문자열은 프로그램 전체 수명 동안 유효합니다";
// 주의: 'static을 남용하지 마세요
// 대부분의 경우 더 짧은 라이프타임이면 충분합니다
3.5 라이프타임 생략 규칙
Rust 컴파일러는 3가지 규칙으로 라이프타임을 자동 추론합니다.
1. 각 참조 매개변수는 고유한 라이프타임을 받는다
2. 참조 매개변수가 하나뿐이면, 반환 타입의 라이프타임은 그것을 따른다
3. 메서드에서 `&self` 또는 `&mut self`가 있으면, 반환 타입의 라이프타임은 `self`를 따른다
// 라이프타임 생략 적용 - 규칙 2
fn first_word(s: &str) -> &str {
// 컴파일러가 fn first_word<'a>(s: &'a str) -> &'a str 로 추론
let bytes = s.as_bytes();
for (i, &item) in bytes.iter().enumerate() {
if item == b' ' {
return &s[0..i];
}
}
&s[..]
}
4. 열거형과 패턴 매칭
4.1 열거형(enum)
Rust의 열거형은 다른 언어보다 훨씬 강력합니다. 각 변형(variant)에 데이터를 포함할 수 있습니다.
// 기본 열거형
enum Direction {
Up,
Down,
Left,
Right,
}
// 데이터를 포함하는 열거형
enum Message {
Quit, // 데이터 없음
Move { x: i32, y: i32 }, // 이름 있는 필드
Write(String), // 단일 String
ChangeColor(i32, i32, i32), // 세 개의 i32
}
impl Message {
fn call(&self) {
match self {
Message::Quit => println!("종료"),
Message::Move { x, y } => println!("이동: ({}, {})", x, y),
Message::Write(text) => println!("메시지: {}", text),
Message::ChangeColor(r, g, b) => {
println!("색상 변경: ({}, {}, {})", r, g, b)
}
}
}
}
4.2 Option 타입
Rust에는 null이 없습니다. 대신 `Option` 열거형을 사용합니다.
enum Option<T> {
None,
Some(T),
}
fn divide(numerator: f64, denominator: f64) -> Option<f64> {
if denominator == 0.0 {
None
} else {
Some(numerator / denominator)
}
}
fn main() {
let result = divide(10.0, 3.0);
// match로 처리
match result {
Some(value) => println!("결과: {:.2}", value),
None => println!("0으로 나눌 수 없습니다"),
}
// if let으로 간결하게
if let Some(value) = divide(10.0, 0.0) {
println!("결과: {}", value);
} else {
println!("나눗셈 실패");
}
// unwrap_or로 기본값 지정
let safe_result = divide(10.0, 0.0).unwrap_or(0.0);
println!("안전한 결과: {}", safe_result);
}
4.3 패턴 매칭(match)
`match`는 Rust에서 가장 강력한 제어 흐름 구문 중 하나입니다.
enum Coin {
Penny,
Nickel,
Dime,
Quarter(UsState),
}
enum UsState {
Alabama,
Alaska,
Arizona,
// ...
}
fn value_in_cents(coin: &Coin) -> u8 {
match coin {
Coin::Penny => {
println!("행운의 동전!");
1
}
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter(state) => {
println!("주 쿼터: {:?}", state);
25
}
}
}
4.4 고급 패턴 매칭
fn classify_number(n: i32) {
match n {
// 범위 매칭
1..=12 => println!("{}월", n),
13..=19 => println!("십대"),
// 가드 조건
x if x % 2 == 0 => println!("짝수: {}", x),
x if x < 0 => println!("음수: {}", x),
// 다중 패턴
20 | 30 | 40 => println!("10의 배수"),
// 나머지 모두
_ => println!("기타: {}", n),
}
}
// 구조체 디스트럭처링
struct Point {
x: f64,
y: f64,
}
fn describe_point(point: &Point) {
match point {
Point { x: 0.0, y: 0.0 } => println!("원점"),
Point { x, y: 0.0 } => println!("x축 위: {}", x),
Point { x: 0.0, y } => println!("y축 위: {}", y),
Point { x, y } => println!("({}, {})", x, y),
}
}
5. 에러 처리
5.1 Result 타입
Rust는 복구 가능한 에러에 `Result`를 사용합니다.
use std::fs::File;
use std::io::{self, Read};
enum Result<T, E> {
Ok(T),
Err(E),
}
fn read_file_content(path: &str) -> Result<String, io::Error> {
let mut file = File::open(path)?;
let mut content = String::new();
file.read_to_string(&mut content)?;
Ok(content)
}
fn main() {
match read_file_content("config.toml") {
Ok(content) => println!("파일 내용: {}", content),
Err(e) => eprintln!("파일 읽기 실패: {}", e),
}
}
5.2 ? 연산자
`?` 연산자는 에러 전파를 간결하게 만듭니다.
use std::fs;
use std::io;
use std::num::ParseIntError;
#[derive(Debug)]
enum AppError {
IoError(io::Error),
ParseError(ParseIntError),
}
impl From<io::Error> for AppError {
fn from(e: io::Error) -> Self {
AppError::IoError(e)
}
}
impl From<ParseIntError> for AppError {
fn from(e: ParseIntError) -> Self {
AppError::ParseError(e)
}
}
fn read_and_parse(path: &str) -> Result<i32, AppError> {
let content = fs::read_to_string(path)?; // io::Error -> AppError
let number = content.trim().parse::<i32>()?; // ParseIntError -> AppError
Ok(number * 2)
}
5.3 anyhow와 thiserror
실전에서는 `anyhow`와 `thiserror` 크레이트를 많이 사용합니다.
// thiserror - 라이브러리용 구체적인 에러 타입 정의
use thiserror::Error;
#[derive(Error, Debug)]
enum DatabaseError {
#[error("연결 실패: {0}")]
ConnectionFailed(String),
#[error("쿼리 실행 에러: {0}")]
QueryError(String),
#[error("레코드를 찾을 수 없음: {id}")]
NotFound { id: u64 },
}
// anyhow - 애플리케이션용 간편한 에러 처리
use anyhow::{Context, Result};
fn load_config() -> Result<Config> {
let content = fs::read_to_string("config.toml")
.context("설정 파일을 읽을 수 없습니다")?;
let config: Config = toml::from_str(&content)
.context("설정 파일 파싱에 실패했습니다")?;
Ok(config)
}
5.4 panic과 복구 불가능한 에러
// panic!은 프로그램을 즉시 중단
fn check_positive(n: i32) {
if n < 0 {
panic!("음수가 입력되었습니다: {}", n);
}
}
// 배열 인덱스 범위 초과도 panic
let v = vec![1, 2, 3];
// let element = v[99]; // panic!
// 안전한 접근
match v.get(99) {
Some(value) => println!("값: {}", value),
None => println!("인덱스 범위 초과"),
}
6. 구조체와 트레이트
6.1 구조체(struct) 정의
#[derive(Debug, Clone)]
struct User {
username: String,
email: String,
age: u32,
active: bool,
}
impl User {
// 생성자 패턴 (관례적으로 new)
fn new(username: String, email: String, age: u32) -> Self {
User {
username,
email,
age,
active: true,
}
}
// 메서드 (&self로 불변 빌림)
fn is_adult(&self) -> bool {
self.age >= 18
}
// 가변 메서드 (&mut self)
fn deactivate(&mut self) {
self.active = false;
}
// 소유권을 가져가는 메서드
fn into_username(self) -> String {
self.username
}
}
fn main() {
let mut user = User::new(
"rustacean".to_string(),
"rust@example.com".to_string(),
25,
);
println!("성인 여부: {}", user.is_adult());
user.deactivate();
println!("사용자: {:?}", user);
}
6.2 트레이트(Trait)
트레이트는 공유 동작을 정의하는 방법입니다. 다른 언어의 인터페이스와 유사합니다.
trait Summary {
fn summarize_author(&self) -> String;
// 기본 구현 제공 가능
fn summarize(&self) -> String {
format!("{}님의 글 더 읽기...", self.summarize_author())
}
}
struct Article {
title: String,
author: String,
content: String,
}
impl Summary for Article {
fn summarize_author(&self) -> String {
self.author.clone()
}
fn summarize(&self) -> String {
format!("{}, by {} - {}...",
self.title, self.author,
&self.content[..50.min(self.content.len())]
)
}
}
struct Tweet {
username: String,
content: String,
}
impl Summary for Tweet {
fn summarize_author(&self) -> String {
format!("@{}", self.username)
}
// summarize는 기본 구현 사용
}
6.3 제네릭과 Trait Bound
// 제네릭 함수 + 트레이트 바운드
fn notify(item: &impl Summary) {
println!("속보! {}", item.summarize());
}
// 동일한 표현 (트레이트 바운드 문법)
fn notify_verbose<T: Summary>(item: &T) {
println!("속보! {}", item.summarize());
}
// 복수의 트레이트 바운드
fn display_and_summarize<T: Summary + std::fmt::Display>(item: &T) {
println!("표시: {}", item);
println!("요약: {}", item.summarize());
}
// where 절로 가독성 향상
fn complex_function<T, U>(t: &T, u: &U) -> String
where
T: Summary + Clone,
U: std::fmt::Display + std::fmt::Debug,
{
format!("{} - {:?}", t.summarize(), u)
}
6.4 제네릭 구조체
struct Stack<T> {
elements: Vec<T>,
}
impl<T> Stack<T> {
fn new() -> Self {
Stack {
elements: Vec::new(),
}
}
fn push(&mut self, item: T) {
self.elements.push(item);
}
fn pop(&mut self) -> Option<T> {
self.elements.pop()
}
fn peek(&self) -> Option<&T> {
self.elements.last()
}
fn is_empty(&self) -> bool {
self.elements.is_empty()
}
fn size(&self) -> usize {
self.elements.len()
}
}
// 특정 타입에 대한 추가 구현
impl<T: std::fmt::Display> Stack<T> {
fn print_top(&self) {
if let Some(top) = self.peek() {
println!("최상단: {}", top);
}
}
}
7. 비동기 프로그래밍
7.1 async/await 기초
Rust의 비동기 프로그래밍은 `async`/`await` 키워드를 사용합니다.
// async fn은 Future를 반환
async fn fetch_data(url: &str) -> Result<String, reqwest::Error> {
let response = reqwest::get(url).await?;
let body = response.text().await?;
Ok(body)
}
// async 블록
let future = async {
let data = fetch_data("https://api.example.com/data").await;
println!("데이터 수신 완료");
data
};
7.2 Tokio 런타임
Rust의 가장 인기 있는 비동기 런타임인 Tokio를 사용하는 방법입니다.
use tokio;
use std::time::Duration;
#[tokio::main]
async fn main() {
// 동시에 여러 작업 실행
let (result1, result2) = tokio::join!(
async_task("작업1", 2),
async_task("작업2", 1),
);
println!("결과: {:?}, {:?}", result1, result2);
}
async fn async_task(name: &str, seconds: u64) -> String {
println!("{} 시작", name);
tokio::time::sleep(Duration::from_secs(seconds)).await;
println!("{} 완료", name);
format!("{} 결과", name)
}
7.3 채널과 동시성
use tokio::sync::mpsc;
#[tokio::main]
async fn main() {
// 다중 생산자, 단일 소비자 채널
let (tx, mut rx) = mpsc::channel::<String>(100);
// 여러 생산자 생성
for i in 0..5 {
let tx_clone = tx.clone();
tokio::spawn(async move {
let msg = format!("메시지 {}", i);
tx_clone.send(msg).await.unwrap();
});
}
// 원본 tx 드롭 (모든 생산자가 끝나면 채널 종료)
drop(tx);
// 소비자
while let Some(message) = rx.recv().await {
println!("수신: {}", message);
}
}
7.4 Mutex와 공유 상태
use std::sync::Arc;
use tokio::sync::Mutex;
#[tokio::main]
async fn main() {
let counter = Arc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..10 {
let counter = Arc::clone(&counter);
let handle = tokio::spawn(async move {
let mut num = counter.lock().await;
*num += 1;
});
handles.push(handle);
}
for handle in handles {
handle.await.unwrap();
}
println!("최종 카운터: {}", *counter.lock().await);
}
8. Cargo 패키지 매니저
8.1 Cargo.toml 구조
[package]
name = "my-project"
version = "0.1.0"
edition = "2021"
authors = ["Developer <dev@example.com>"]
description = "A sample Rust project"
license = "MIT"
[dependencies]
serde = { version = "1.0", features = ["derive"] }
tokio = { version = "1", features = ["full"] }
reqwest = { version = "0.12", features = ["json"] }
anyhow = "1.0"
thiserror = "2.0"
clap = { version = "4", features = ["derive"] }
[dev-dependencies]
criterion = "0.5"
mockall = "0.13"
[profile.release]
opt-level = 3
lto = true
codegen-units = 1
strip = true
8.2 주요 Cargo 명령어
프로젝트 생성
cargo new my-project # 바이너리 프로젝트
cargo new my-lib --lib # 라이브러리 프로젝트
빌드와 실행
cargo build # 디버그 빌드
cargo build --release # 릴리스 빌드
cargo run # 빌드 후 실행
cargo run -- --arg1 value # 인자 전달
테스트
cargo test # 모든 테스트 실행
cargo test test_name # 특정 테스트만
cargo test -- --nocapture # 출력 표시
검사와 분석
cargo check # 컴파일 확인 (빌드보다 빠름)
cargo clippy # 린트 검사
cargo fmt # 코드 포매팅
문서
cargo doc --open # 문서 생성 후 브라우저 열기
의존성 관리
cargo add serde # 의존성 추가
cargo update # 의존성 업데이트
cargo tree # 의존성 트리 확인
8.3 워크스페이스
대규모 프로젝트는 워크스페이스로 관리합니다.
루트 Cargo.toml
[workspace]
members = [
"crates/core",
"crates/api",
"crates/cli",
]
[workspace.dependencies]
serde = { version = "1.0", features = ["derive"] }
tokio = { version = "1", features = ["full"] }
crates/core/Cargo.toml
[package]
name = "my-core"
version = "0.1.0"
edition = "2021"
[dependencies]
serde = { workspace = true }
8.4 Crate 배포
crates.io 계정 설정
cargo login
배포 전 검사
cargo publish --dry-run
실제 배포
cargo publish
9. 실전 Rust
9.1 CLI 도구 (clap)
use clap::Parser;
use std::path::PathBuf;
#[derive(Parser, Debug)]
#[command(name = "file-analyzer")]
#[command(about = "파일 분석 도구", long_about = None)]
struct Cli {
/// 분석할 파일 경로
#[arg(short, long)]
path: PathBuf,
/// 출력 형식
#[arg(short, long, default_value = "text")]
format: String,
/// 상세 출력
#[arg(short, long)]
verbose: bool,
/// 최대 깊이
#[arg(short, long, default_value_t = 3)]
depth: u32,
}
fn main() {
let cli = Cli::parse();
if cli.verbose {
println!("파일 경로: {:?}", cli.path);
println!("출력 형식: {}", cli.format);
println!("최대 깊이: {}", cli.depth);
}
analyze_file(&cli.path, cli.depth);
}
fn analyze_file(path: &PathBuf, depth: u32) {
println!("분석 중: {:?} (깊이: {})", path, depth);
// 파일 분석 로직...
}
9.2 웹 서버 (Axum)
use axum::{
extract::{Path, State},
http::StatusCode,
response::Json,
routing::{get, post},
Router,
};
use serde::{Deserialize, Serialize};
use std::sync::Arc;
use tokio::sync::Mutex;
#[derive(Debug, Serialize, Deserialize, Clone)]
struct Todo {
id: u64,
title: String,
completed: bool,
}
type AppState = Arc<Mutex<Vec<Todo>>>;
#[tokio::main]
async fn main() {
let state: AppState = Arc::new(Mutex::new(Vec::new()));
let app = Router::new()
.route("/todos", get(list_todos).post(create_todo))
.route("/todos/:id", get(get_todo))
.with_state(state);
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000")
.await
.unwrap();
println!("서버 실행: http://localhost:3000");
axum::serve(listener, app).await.unwrap();
}
async fn list_todos(
State(state): State<AppState>,
) -> Json<Vec<Todo>> {
let todos = state.lock().await;
Json(todos.clone())
}
async fn create_todo(
State(state): State<AppState>,
Json(payload): Json<CreateTodo>,
) -> (StatusCode, Json<Todo>) {
let mut todos = state.lock().await;
let todo = Todo {
id: todos.len() as u64 + 1,
title: payload.title,
completed: false,
};
todos.push(todo.clone());
(StatusCode::CREATED, Json(todo))
}
#[derive(Deserialize)]
struct CreateTodo {
title: String,
}
async fn get_todo(
State(state): State<AppState>,
Path(id): Path<u64>,
) -> Result<Json<Todo>, StatusCode> {
let todos = state.lock().await;
todos
.iter()
.find(|t| t.id == id)
.cloned()
.map(Json)
.ok_or(StatusCode::NOT_FOUND)
}
9.3 WebAssembly (WASM)
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn fibonacci(n: u32) -> u64 {
if n <= 1 {
return n as u64;
}
let mut a: u64 = 0;
let mut b: u64 = 1;
for _ in 2..=n {
let temp = b;
b = a + b;
a = temp;
}
b
}
#[wasm_bindgen]
pub struct ImageProcessor {
width: u32,
height: u32,
pixels: Vec<u8>,
}
#[wasm_bindgen]
impl ImageProcessor {
#[wasm_bindgen(constructor)]
pub fn new(width: u32, height: u32) -> Self {
ImageProcessor {
width,
height,
pixels: vec![0; (width * height * 4) as usize],
}
}
pub fn grayscale(&mut self) {
for chunk in self.pixels.chunks_mut(4) {
let avg = ((chunk[0] as u16 + chunk[1] as u16 + chunk[2] as u16) / 3) as u8;
chunk[0] = avg;
chunk[1] = avg;
chunk[2] = avg;
}
}
pub fn pixels(&self) -> *const u8 {
self.pixels.as_ptr()
}
}
10. Rust in 2026
10.1 Linux 커널의 Rust
Linux 6.1(2022)부터 Rust가 공식적으로 커널에 도입되었고, 2026년 현재 드라이버, 파일시스템, 네트워크 서브시스템 등에서 Rust 코드가 확대되고 있습니다.
- **드라이버**: GPU, NVMe 등 새로운 드라이버를 Rust로 작성
- **바인딩**: 기존 C 커널 API에 대한 안전한 Rust 바인딩 확충
- **도구**: `rustfmt`, `clippy` 등 커널 Rust 툴체인 안정화
10.2 Android와 모바일
Google은 Android의 새로운 시스템 컴포넌트를 Rust로 작성하고 있습니다.
- Bluetooth 스택, 키스토어, DNS 리졸버 등에 Rust 적용
- 메모리 안전 취약점이 크게 감소
- Android의 Rust 코드 비율이 지속적으로 증가
10.3 클라우드 인프라
AWS, Azure, GCP 모두 핵심 인프라에 Rust를 활용하고 있습니다.
| 조직 | 프로젝트 | 설명 |
| --- | --- | --- |
| AWS | Firecracker | 서버리스 VM 관리 |
| AWS | Bottlerocket | 컨테이너 전용 OS |
| Cloudflare | Pingora | HTTP 프록시 엔진 |
| Discord | 메시지 인프라 | 읽기 상태 서비스 재작성 |
| Figma | 서버 사이드 | 멀티플레이어 서버 |
| 1Password | 핵심 엔진 | 크로스 플랫폼 코어 |
10.4 Rust의 미래 전망
2026년 기준으로 Rust의 미래는 밝습니다.
**성장 영역**:
- **임베디드/IoT**: `no_std` 환경에서의 안전한 프로그래밍
- **게임 개발**: Bevy 엔진의 성숙
- **AI/ML 인프라**: PyTorch, Hugging Face 등에서 핵심 컴포넌트로 Rust 사용
- **블록체인**: Solana, Polkadot 등 주요 블록체인이 Rust 기반
**언어 발전**:
- **비동기 개선**: async trait 안정화, async closure
- **에디션**: Rust 2024 에디션의 안정화
- **GAT**: 제네릭 연관 타입의 활용 확대
- **컴파일 속도**: 빌드 시간 지속 개선
마무리
Rust는 단순히 C/C++의 대체제가 아닙니다. 소유권 시스템과 타입 시스템을 통해 **안전성과 성능을 동시에** 달성하는 새로운 패러다임을 제시합니다.
Rust를 배우는 과정에서 "소유권 싸움(fighting the borrow checker)"을 경험하게 되지만, 이는 컴파일러가 런타임에 발생할 버그를 미리 잡아주는 것입니다. 시간이 지나면 소유권 시스템이 자연스러워지고, 다른 언어에서도 더 안전한 코드를 작성하게 됩니다.
Rust 입문자에게 권장하는 학습 순서:
1. **The Rust Programming Language (The Book)** 읽기
2. **Rustlings** 연습 문제 풀기
3. 소규모 CLI 도구 만들기
4. 웹 서버 또는 API 구축
5. 오픈소스 프로젝트 기여
Rust의 커뮤니티는 친절하고 활발합니다. 공식 포럼, Discord, 그리고 Reddit의 r/rust에서 도움을 받을 수 있습니다. 2026년, Rust는 시스템 프로그래밍의 미래를 이끌어가고 있습니다.
현재 단락 (1/767)
1. [왜 Rust인가](#1-왜-rust인가)