목차
- 왜 Rust인가
- 소유권(Ownership)
- 라이프타임
- 열거형과 패턴 매칭
- 에러 처리
- 구조체와 트레이트
- 비동기 프로그래밍
- Cargo 패키지 매니저
- 실전 Rust
- 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가지 규칙으로 요약됩니다.
- Rust의 모든 값은 소유자(owner) 가 있다
- 한 시점에 소유자는 단 하나뿐이다
- 소유자가 스코프를 벗어나면 값은 자동으로 해제된다
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가지 규칙으로 라이프타임을 자동 추론합니다.
- 각 참조 매개변수는 고유한 라이프타임을 받는다
- 참조 매개변수가 하나뿐이면, 반환 타입의 라이프타임은 그것을 따른다
- 메서드에서
&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 입문자에게 권장하는 학습 순서:
- The Rust Programming Language (The Book) 읽기
- Rustlings 연습 문제 풀기
- 소규모 CLI 도구 만들기
- 웹 서버 또는 API 구축
- 오픈소스 프로젝트 기여
Rust의 커뮤니티는 친절하고 활발합니다. 공식 포럼, Discord, 그리고 Reddit의 r/rust에서 도움을 받을 수 있습니다. 2026년, Rust는 시스템 프로그래밍의 미래를 이끌어가고 있습니다.
현재 단락 (1/767)
1. [왜 Rust인가](#1-왜-rust인가)