Rust

82 posts
cargo fmt로 Rust 코드 스타일 자동 정리하기

cargo fmt로 Rust 코드 스타일 자동 정리하기

팀에서 코드 리뷰를 하다 보면 로직과 무관한 스타일 논쟁에 시간을 쓸 때가 있어요. 중괄호를 같은 줄에 둘지 다음 줄에 둘지, use 구문을 어떻게 묶을지, 한 줄이 몇 글자를 넘으면 줄바꿈할지... 이런 토론이 쌓이면 정작 중요한 설계나 로직 리뷰에 집중하기 어렵습니다 😅 Rust 생태계에서는 이 문제를 rustfmt라는 공식 포매터로 깔끔하게 해결합니다. cargo fmt 한 번이면 코드 스타일이 일관되게 정리되니까 팀원들은 포매팅에 신경 쓸 필요 없이 코드 자체에만 집중할 수 있죠. 이번 글에서는 rustfmt의 설치부터 설

cargo clippy로 Rust 코드 품질 높이기

cargo clippy로 Rust 코드 품질 높이기

Rust 컴파일러는 워낙 꼼꼼해서 컴파일만 통과하면 꽤 안심이 되죠. 하지만 "컴파일은 되는데 이게 정말 좋은 코드인가?"라는 질문에는 컴파일러가 답해주지 않습니다. 불필요한 clone() 호출, 더 간결하게 쓸 수 있는 패턴, 성능을 깎아먹는 습관적인 코드... 이런 건 컴파일러의 관심사가 아니거든요. Clippy는 바로 이 영역을 담당하는 Rust의 공식 린트 도구입니다. 700개가 넘는 린트 규칙으로 코드를 분석해서 잠재적인 버그부터 스타일 개선 사항까지 짚어줍니다. 이번 글에서는 Clippy의 설치와 기본 사용법, 주요 린트

rustup으로 Rust 툴체인 관리하기

rustup으로 Rust 툴체인 관리하기

Rust를 처음 시작할 때 공식 사이트에서 안내하는 대로 설치 스크립트를 실행하면 rustup이라는 도구가 함께 깔립니다. 처음에는 "Rust 설치 프로그램"쯤으로 생각하고 넘어가기 쉬운데, 사실 rustup은 그보다 훨씬 많은 일을 해요. 컴파일러 버전을 바꾸거나 nightly 기능을 잠깐 써보거나 팀 전체의 Rust 버전을 맞추거나 WebAssembly로 크로스 컴파일하는 것까지 전부 rustup이 담당합니다. 이번 글에서는 rustup의 설치부터 툴체인 관리, 컴포넌트와 타겟 설정, 팀 단위 버전 고정까지 살펴보겠습니다. ru

Tower Layer 직접 만들기: 커스텀 미들웨어 작성 가이드

Tower Layer 직접 만들기: 커스텀 미들웨어 작성 가이드

Tower 미들웨어 실전에서 본 빌트인 미들웨어로 대부분의 자리는 커버되지만, 가끔은 직접 만들어야 하는 순간이 옵니다. 사내 인증 토큰 검증, 도메인 특화 메트릭 수집, 비표준 헤더 처리 같은 자리죠. 이번 글에서는 Tower의 Service와 Layer를 직접 구현해서 미들웨어를 작성하는 방법을 정리해보겠습니다. 비동기 future를 직접 만드는 패턴까지 포함해서요. 입문 개념은 Tower 입문에서 다뤘으니, 이 글은 그 위에서 한 단계 깊이 들어가는 내용입니다. 만약 Future의 poll, Waker, Pin 같은 단어가 아

Rhai 입문: Rust 앱에 임베디드 스크립트 박아 넣기

Rhai 입문: Rust 앱에 임베디드 스크립트 박아 넣기

Rust로 서비스를 짜다 보면 가끔 이런 욕심이 생깁니다. "이 분기 로직을 코드 변경 없이 운영자가 살짝 바꿀 수 있으면 좋을 텐데", "고객사마다 다른 헤더 변환 규칙을 그때그때 다른 바이너리로 빌드하긴 너무 무거운데"처럼요. 이런 상황을 위한 도구가 바로 임베디드 스크립트 엔진입니다. 이번 글에서는 Rust 생태계에서 자주 쓰이는 Rhai 스크립트 엔진을 소개합니다. 호스트 Rust 코드에 박아 넣는 방법부터 Rhai 자체 문법까지 한 번에 살펴보겠습니다. 임베디드 스크립트가 필요한 순간 서비스 본체는 Rust로 단단하게 컴파

Axum으로 REST API 서버 만들기: 라우팅, 추출자, 상태 관리

Axum으로 REST API 서버 만들기: 라우팅, 추출자, 상태 관리

Rust로 HTTP 서버를 짜다 보면 프레임워크 선택에서 한 번씩 막힙니다. actix-web은 성능이 검증됐지만 액터 모델이 낯설고, warp는 함수형 스타일이 깔끔한데 타입 에러가 미로처럼 느껴질 때가 있습니다. Axum은 Tokio 팀이 만든 웹 프레임워크입니다. "Tower 위의 얇은 라우팅 레이어"를 표방하는데, 이게 생각보다 실용적입니다. 타임아웃이나 인증 미들웨어를 Tower로 짜두면 Axum에 그대로 끼울 수 있고, 핸들러 함수 시그니처에 타입만 선언해두면 Axum이 요청에서 필요한 데이터를 알아서 꺼내줍니다. 이 글

Rust tokio::io::duplex: 실제 소켓 없이 비동기 I/O 코드 테스트하기

Rust tokio::io::duplex: 실제 소켓 없이 비동기 I/O 코드 테스트하기

Tokio로 TCP 에코 서버 같은 네트워크 코드를 짜고 나면 한 가지 고민이 생깁니다. 이걸 어떻게 테스트하지? 보통은 테스트 안에서 진짜 TcpListener로 포트를 열고, 클라이언트로 접속해서 데이터를 주고받습니다. 그런데 이 방식은 포트가 겹치면 충돌하고, 테스트를 병렬로 돌리기 까다롭고, 운영체제의 네트워크 스택을 거치느라 은근히 느립니다. 😮‍💨 그래서 Tokio는 tokio::io::duplex라는 도구를 제공합니다. 메모리 위에 소켓처럼 동작하는 양방향 파이프를 만들어주는데요. 실제 네트워크 없이도 "쓰면 반대편

Tauri로 가벼운 데스크톱 앱 만들기

Tauri로 가벼운 데스크톱 앱 만들기

웹 개발자라면 한 번쯤 "내가 만든 웹 앱을 데스크톱 앱으로 배포할 수 있으면 좋겠다"고 생각해 보신 적 있을 겁니다. Electron이 이 영역을 오랫동안 지배해 왔지만, 앱 하나에 Chromium 전체를 번들하다 보니 설치 파일이 100MB를 넘어가는 건 일상이었죠 😅 Tauri는 이 문제를 풀려고 만들어진 프레임워크입니다. 프론트엔드는 기존 웹 기술을 그대로 쓰되 백엔드를 Rust로 작성하고, OS의 네이티브 웹뷰를 활용해서 앱 크기를 수 MB 수준으로 줄여 줘요. 이번 글에서는 Tauri 2로 데스크톱 앱을 처음부터 만들어

Rust Tower 미들웨어 실전: 타임아웃, 재시도, 레이트 리미트

Rust Tower 미들웨어 실전: 타임아웃, 재시도, 레이트 리미트

Tower 입문에서 Service/Layer/ServiceBuilder를 둘러봤다면, 이번에는 Tower가 기본으로 제공하는 미들웨어를 실무 시나리오에 맞춰 끼워보겠습니다. 외부 API를 호출하는 서비스나 가용성 보장이 필요한 게이트웨이를 만든다고 가정하면 거의 다 이 안에서 해결됩니다. 이 글에서 다루는 미들웨어는 모두 tower 크레이트의 기본 기능에 들어 있어서, Cargo.toml에 다음만 추가하면 시작할 수 있습니다. 타임아웃: 응답 시간 제한 가장 자주 쓰이는 미들웨어가 타임아웃입니다. "이 호출은 N초 안에 끝나야 한다

Rust tokio::time::timeout: 비동기 작업에 시간 제한 걸기

Rust tokio::time::timeout: 비동기 작업에 시간 제한 걸기

비동기 코드를 짜다 보면 외부에 의존하는 작업을 마주하게 됩니다. 외부 API 호출, 데이터베이스 쿼리, 다른 서비스로의 gRPC 요청 같은 것들이죠. 이런 작업은 대부분 빠르게 끝나지만, 상대방이 느려지거나 응답을 아예 안 주면 우리 코드는 그 자리에서 하염없이 기다리게 됩니다. 이럴 때 필요한 게 시간 제한입니다. "이 작업은 3초 안에 끝나야 하고, 안 끝나면 포기한다"는 약속을 거는 거죠. Tokio는 이를 위해 tokio::time::timeout 함수를 제공합니다. 이번 글에서는 이 함수의 기본 사용법부터, 한 가지 짚고

Rust Tower 입문: Service 트레이트와 Layer로 미들웨어 합성하기

Rust Tower 입문: Service 트레이트와 Layer로 미들웨어 합성하기

Rust로 HTTP 서버를 짜다 보면 신기한 일이 벌어지는데요. Hyper, Axum, Tonic 같은 프레임워크가 다 다르게 생겼는데, 한 번 만든 미들웨어를 그 사이에 그대로 옮겨 써도 작동합니다. 비밀은 이들이 공유하는 한 가지 추상화에 있는데요. 바로 Tower입니다. 이번 글에서는 Tower의 두 핵심 트레이트인 Service와 Layer를 살펴보고, ServiceBuilder로 미들웨어를 깔끔하게 합성하는 방법까지 정리해보겠습니다. 빌트인 미들웨어 활용은 Tower 미들웨어 실전에서, 직접 미들웨어를 만드는 방법은 Tow

Rust 기초: Cow로 불필요한 복사 줄이기

Rust 기초: Cow로 불필요한 복사 줄이기

문자열을 정규화하는 함수를 만든다고 해볼게요. 공백을 다듬고 소문자로 바꾸는 작업이 필요한데, 입력이 이미 깔끔할 수도 있습니다. 간단하죠. 그런데 한 가지 찜찜한 점이 있습니다. 입력이 이미 정규화된 상태라면 어떻게 될까요? 아무 변화도 없는데 to_lowercase()가 호출되는 순간 새로운 String이 힙에 할당됩니다. 초당 수백만 번 호출되는 코드라면 이 낭비가 꽤 아프게 다가오죠. "변경이 필요할 때만 복사하고, 그 외엔 빌린 채로 쓰자"는 아이디어를 타입으로 표현한 게 바로 Cow<'a, B>입니다. 이 글에서는 Cow

Rust anyhow 크레이트: 애플리케이션 에러를 간편하게 처리하기

Rust anyhow 크레이트: 애플리케이션 에러를 간편하게 처리하기

Rust 에러 처리를 다루면서 라이브러리용 에러 타입을 깔끔하게 정의하는 thiserror는 살펴봤는데요. 정작 그 단짝인 anyhow는 아직 다루지 않았습니다. 둘은 보통 한 쌍으로 거론되지만 역할이 정반대거든요. 애플리케이션 코드를 짜다 보면 함수 하나에서 파일도 읽고, 문자열도 파싱하고, 네트워크도 호출합니다. 그러면 std::io::Error, ParseIntError 등 종류가 다른 에러가 마구 쏟아지는데요. 이걸 일일이 enum으로 묶어 정의하는 건 과합니다. 어차피 최종적으로는 "어디서 왜 실패했는지" 로그를 남기고 프

Rust 기초: Borrow와 ToOwned 트레이트

Rust 기초: Borrow와 ToOwned 트레이트

Rust로 HashMap을 다루다 보면 한 번쯤 이런 의문이 생깁니다. 키로 String을 넣었는데, 조회할 때는 &str을 넘겨도 잘 찾아지는 게 신기하지 않나요? 이게 우연이 아니라 Borrow라는 트레이트가 만들어주는 보장 덕분인데요. 그리고 그 반대쪽, 즉 빌린 값을 다시 소유권이 있는 값으로 되돌리는 역할을 하는 게 ToOwned 트레이트입니다. 이 글에서는 이 두 트레이트가 어떤 계약을 맺고 있고, 왜 짝을 이루는지 알아보겠습니다. AsRef 트레이트와 비슷해 보이지만 미묘하게 다른 지점이 핵심입니다. Borrow 트레이

Rust tokio::fs: 비동기 파일 I/O와 그 한계

Rust tokio::fs: 비동기 파일 I/O와 그 한계

std::fs 함수는 모두 동기적입니다. 호출하면 그 자리에서 디스크를 기다리며 멈춰 있죠. Tokio 같은 비동기 런타임 위에서 이 함수를 그냥 부르면, 파일을 기다리는 동안 같은 스레드에서 돌아야 할 다른 태스크가 같이 멈춰버립니다. 이번 글에서는 이 문제를 풀기 위한 tokio::fs 모듈을 살펴보고, 한 가지 흥미로운 사실(사실은 진짜 비동기가 아님)을 짚어보겠습니다. tokio::fs는 std::fs의 비동기 버전 tokio::fs는 std::fs와 거의 같은 인터페이스를 비동기 버전으로 제공하는데요. 함수 이름과 시그니처

Rust의 let else: 패턴 매칭 실패 시 깔끔하게 조기 반환하기

Rust의 let else: 패턴 매칭 실패 시 깔끔하게 조기 반환하기

Option이나 Result를 다루다 보면 비슷한 코드를 자꾸 반복해서 쓰게 되는 순간이 있습니다. 값이 들어 있으면 꺼내서 계속 진행하고, 그렇지 않으면 일찍 함수를 빠져나가는 패턴이죠. 값을 꺼내려는 게 코드의 본 의도인데, 정작 화면에서 가장 눈에 띄는 건 if let과 그 뒤에 따라붙는 두 갈래의 분기죠. Rust 1.65에서 안정화된 let ... else 구문은 바로 이 패턴을 한 줄로 정리해주는 도구입니다. 이번 글에서는 let else가 어떤 모양이고, if let이나 match와 어떻게 다른지, 그리고 어떤 상황에서

Rust의 에러 처리: 예외 대신 값으로 다루는 법

Rust의 에러 처리: 예외 대신 값으로 다루는 법

자바스크립트로 파일을 읽거나 파이썬으로 API를 호출해본 경험이 있으시다면, 아마 try/catch나 try/except로 예외를 잡는 방식이 익숙하실 겁니다. 그런데 Rust 코드를 처음 보면 이상한 점이 눈에 들어옵니다. 분명히 파일을 여는데 try도 없고, 함수 시그니처에 throws도 없고, 대신 Result<T, E>라는 낯선 타입이 반환됩니다. 🤔 이번 글에서는 다른 언어와 비교했을 때 Rust 에러 처리가 가지는 가장 특이한 지점들과, 일상적인 실패와 버그를 Rust가 어떻게 갈라놓는지를 정리해보겠습니다. 예외가 아니

Rust BufReader와 BufWriter: 버퍼링된 파일 I/O로 효율 챙기기

Rust BufReader와 BufWriter: 버퍼링된 파일 I/O로 효율 챙기기

std::fs 기초에서 본 read_to_string은 편합니다. 한 줄로 파일을 통째로 읽어 String으로 돌려주죠. 하지만 5GB짜리 로그 파일에 같은 함수를 쓴다면? 메모리에 5GB가 그대로 올라갑니다. 이번 글에서는 대용량 파일을 효율적으로 다루는 도구인 BufReader/BufWriter를 정리하고, 줄 단위 처리, 적절한 버퍼링, flush 잊지 않기 같은 실무 패턴을 살펴보겠습니다. 왜 버퍼링이 필요한가 파일 시스템 호출(syscall)은 비싼 연산입니다. 한 바이트씩 읽고 쓰면 매번 syscall이 발생해서 성능이

Zellij: Rust로 만든 차세대 터미널 멀티플렉서

Zellij: Rust로 만든 차세대 터미널 멀티플렉서

터미널에서 개발하다 보면 창이 부족해지는 순간이 오죠. 개발 서버 하나 돌리고, 로그 보면서, 또 다른 창에서 Git 작업하고, 테스트도 돌려야 하고... 결국 터미널 탭이 열 개쯤 열려 있는 자신을 발견하게 됩니다. 😅 이런 문제를 해결하려고 tmux 같은 터미널 멀티플렉서를 써보신 분들도 계실 텐데요. 솔직히 tmux는 진입 장벽이 꽤 높습니다. 키 바인딩을 외워야 하고, 설정 파일도 복잡하고, 처음 켜면 뭘 어떻게 해야 하는지 막막하죠. Zellij는 이런 고민을 깔끔하게 해결해주는 차세대 터미널 멀티플렉서입니다. Rust로

Rust Result 메서드 정리: ?, map_err, and_then, 콤비네이터

Rust Result 메서드 정리: ?, map_err, and_then, 콤비네이터

Rust의 에러 처리에서 봤듯이, Rust는 실패 가능성을 Result<T, E> 타입으로 반환 타입에 박아 넣는 언어입니다. 다만 매번 match로 풀어내기엔 코드가 너무 장황해지죠. 그래서 표준 라이브러리는 Result를 다루는 다양한 메서드를 갖춰두고 있습니다. 이번 글에서는 실무에서 자주 만나는 Result 메서드를 용도별로 정리해보겠습니다. 조기 반환에 쓰는 ? 연산자부터, 에러를 변환하는 map_err, 값을 갈아 끼우는 map/and_then, 그리고 회복용 unwrap_or 패밀리까지 한 번에 살펴봅시다. Result

Discord