Rust 기본 원리 24개의 최소한 예제를 통해
Takashi Yamamoto
Infrastructure Engineer · Leapcell

Rust는 안전성, 성능 및 동시성이 뛰어나며 풍부하고 독특한 언어 구조를 갖춘 시스템 프로그래밍 언어입니다. 이 기사에서는 24개의 간결한 코드 예제를 통해 Rust의 핵심 기능을 소개합니다.
패턴 매칭
Rust의 match
표현식은 패턴 매칭을 구현하여 값이 일련의 패턴에 맞는지 확인할 수 있습니다.
let number = Some(42); match number { Some(x) => println!("The number is {}", x), None => println!("There is no number"), }
이 코드는 Option
유형의 다양한 경우를 처리하기 위해 match
표현식을 사용하는 방법을 보여줍니다.
소유권 및 라이프타임
라이프타임 매개변수를 통해 Rust는 참조가 유효하게 유지되고 매달린 포인터를 방지합니다.
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { if x.len() > y.len() { x } else { y } }
이 함수는 두 개의 문자열 슬라이스를 가져와서 더 긴 슬라이스를 반환합니다. 라이프타임 'a
는 반환된 참조가 유효함을 보장합니다.
제네릭
제네릭을 사용하면 정확한 유형을 지정하지 않고도 함수와 구조체를 정의할 수 있습니다.
fn largest<T: PartialOrd + Copy>(list: &[T]) -> T { list.iter().cloned().max_by(|a, b| a.partial_cmp(b).unwrap()).unwrap() }
이 제네릭 함수 largest
는 PartialOrd
및 Copy
특성을 구현하는 모든 유형의 목록에서 최대값을 찾습니다.
트레이트
트레이트는 인터페이스와 유사하며 구현할 수 있는 메서드 집합을 정의합니다.
trait Summary { fn summarize(&self) -> String; }
Summary
트레이트는 객체의 텍스트 요약을 제공하기 위해 모든 유형에서 구현할 수 있습니다.
타입 캐스팅
Rust는 타입 변환을 수행하는 여러 가지 방법을 제공합니다.
let decimal: f64 = 6.0; let integer: i32 = decimal as i32; // 명시적 타입 변환
이 코드는 f64
유형의 값을 i32
로 명시적으로 변환하는 방법을 보여줍니다.
오류 처리
Rust는 Result
유형을 사용하여 잠재적인 오류를 처리합니다.
fn divide(a: f64, b: f64) -> Result<f64, String> { if b == 0.0 { Err("Cannot divide by zero".to_string()) } else { Ok(a / b) } }
이 divide
함수는 제수가 0일 때 오류를 반환합니다.
반복자
반복자는 시퀀스 처리를 위한 Rust의 강력한 추상화입니다.
let a = [1, 2, 3]; let mut iter = a.iter(); while let Some(&item) = iter.next() { println!("{}", item); }
이 코드는 반복자를 사용하여 배열을 순회합니다.
클로저
클로저는 Rust의 익명 함수입니다.
let list = vec![1, 2, 3]; let even_numbers: Vec<i32> = list.into_iter().filter(|&x| x % 2 == 0).collect();
여기서 클로저는 Vec
에서 짝수를 필터링하는 데 사용됩니다.
비동기 프로그래밍
비동기 코드를 사용하면 프로그램이 I/O 작업을 기다리는 동안 다른 작업을 수행할 수 있습니다.
async fn fetch_data() -> Result<(), Error> { // 비동기적으로 데이터를 가져오는 코드 Ok(()) }
이 fetch_data
함수는 비동기적이며 비동기 런타임 내에서 호출할 수 있습니다.
스마트 포인터
스마트 포인터는 추가 기능과 동적 동작을 갖춘 포인터입니다.
use std::rc::Rc; let a = Rc::new(5); let b = Rc::clone(&a);
여기서 Rc<T>
는 참조 횟수가 계산된 스마트 포인터로, 동일한 데이터의 여러 소유자를 허용합니다.
스레드
Rust의 std::thread
모듈은 스레드를 생성하고 관리하는 기능을 제공합니다.
use std::thread; let handle = thread::spawn(|| { println!("Hello from a thread!"); }); handle.join().unwrap();
이 코드는 새 스레드를 생성하고 그 안에 메시지를 출력합니다.
채널
채널은 스레드 간 통신을 위한 Rust의 메커니즘입니다.
use std::sync::mpsc; let (tx, rx) = mpsc::channel(); tx.send("Hello").unwrap(); let message = rx.recv().unwrap();
여기서 채널은 스레드 간에 메시지를 전달하기 위해 생성됩니다.
원자적 타입
원자적 타입은 스레드로부터 안전한 공유 상태를 제공합니다.
use std::sync::atomic::{AtomicUsize, Ordering}; let count = AtomicUsize::new(0);
AtomicUsize
는 다중 스레드 컨텍스트에서 안전하게 사용할 수 있는 부호 없는 정수입니다.
조건부 컴파일
조건부 컴파일을 사용하면 플랫폼 또는 구성에 따라 다른 코드를 컴파일할 수 있습니다.
#[cfg(target_os = "windows")] fn is_windows() -> bool { true }
이 속성 매크로는 대상 운영 체제가 Windows인 경우에만 is_windows
함수를 활성화합니다.
매크로
매크로는 코드를 생성할 수 있는 Rust의 강력한 기능입니다.
#[macro_use] extern crate serde_derive;
여기서 serde_derive
매크로는 직렬화 및 역직렬화 코드 작성을 단순화합니다.
모듈 및 패키지
모듈 시스템을 사용하면 코드를 계층적 구조로 구성할 수 있습니다.
mod my_module { pub fn do_something() { // ... } }
my_module
은 현재 파일 내의 모듈이며 외부에서 액세스할 수 있는 함수 do_something
을 포함합니다.
기능 게이트
기능 게이트는 특정 기능이 오용되는 것을 방지하는 방법입니다.
#![feature(untagged_unions)]
이 속성 매크로는 Rust에서 아직 안정화되지 않은 실험적 untagged_unions
기능을 활성화합니다.
메모리 할당
Rust는 메모리 할당자의 사용자 정의를 허용합니다.
use std::alloc::{GlobalAlloc, Layout}; struct MyAllocator; unsafe impl GlobalAlloc for MyAllocator { unsafe fn alloc(&self, _layout: Layout) -> *mut u8 { // ... } }
여기서 사용자 정의 전역 할당자 MyAllocator
가 정의됩니다.
Raw 포인터
Raw 포인터는 낮은 수준의 메모리 제어를 제공합니다.
let mut v = vec![1, 2, 3]; let ptr: *mut i32 = v.as_mut_ptr();
이 코드는 Vec
에 대한 원시 포인터를 가져와 내부 정수를 직접 조작할 수 있습니다.
Unions
Unions를 사용하면 다른 데이터 유형이 메모리를 공유할 수 있습니다.
union MyUnion { i: i32, f: f32, }
MyUnion
은 i32
또는 f32
를 저장할 수 있지만 한 번에 하나만 저장할 수 있습니다.
Enums
Rust의 Enums는 여러 변형 중 하나일 수 있는 유형을 나타내는 데 사용됩니다.
enum Message { Quit, Move { x: i32, y: i32 }, Write(String), }
Message
enum은 Quit
, 좌표가 있는 Move
또는 문자열을 포함하는 Write
일 수 있습니다.
Destructuring
Destructuring을 사용하면 구조체 또는 튜플에서 값을 추출할 수 있습니다.
let (x, y, z) = (1, 2, 3);
이것은 튜플을 분해하여 동시에 세 개의 변수를 만듭니다.
라이프타임 생략
Rust 컴파일러는 특정 경우에 라이프타임을 자동으로 유추할 수 있습니다.
fn borrow<'a>(x: &'a i32, y: &'a i32) -> &'a i32 { if *x > *y { x } else { y } }
이 함수에서 컴파일러는 라이프타임 매개변수를 자동으로 유추할 수 있습니다.
인라인 어셈블리
인라인 어셈블리를 사용하면 Rust 코드 내에 어셈블리 명령어를 포함할 수 있습니다.
// 특정 아키텍처 및 환경 설정 필요 unsafe { asm!("nop", options(nomem, nostack)); }
이 코드는 asm!
매크로를 사용하여 nop
(no operation) 명령어를 삽입합니다.
저희는 Rust 프로젝트 호스팅을 위한 최고의 선택인 Leapcell입니다.
Leapcell은 웹 호스팅, 비동기 작업 및 Redis를 위한 차세대 서버리스 플랫폼입니다.
다국어 지원
- Node.js, Python, Go 또는 Rust로 개발하십시오.
무료로 무제한 프로젝트 배포
- 사용량에 대해서만 지불하십시오. 요청도, 청구도 없습니다.
탁월한 비용 효율성
- 유휴 요금 없이 사용한 만큼 지불하십시오.
- 예: $25는 평균 응답 시간 60ms에서 694만 건의 요청을 지원합니다.
간소화된 개발자 경험
- 손쉬운 설정을 위한 직관적인 UI.
- 완전 자동화된 CI/CD 파이프라인 및 GitOps 통합.
- 실행 가능한 통찰력을 위한 실시간 메트릭 및 로깅.
손쉬운 확장성과 고성능
- 고도의 동시성을 쉽게 처리할 수 있도록 자동 확장.
- 제로 운영 오버헤드 — 구축에만 집중하십시오.
문서에서 자세히 알아보십시오!
X에서 저희를 팔로우하십시오: @LeapcellHQ