994 posts
Rust 기초: Arc로 스레드 간 데이터 공유하기

Rust 기초: Arc로 스레드 간 데이터 공유하기

Rust의 소유권 시스템은 메모리 안전성을 보장해주지만, 여러 스레드에서 같은 데이터를 공유하려고 하면 컴파일러가 허용하지 않습니다. "한 번에 하나의 소유자만 존재할 수 있다"는 규칙 때문입니다. 소유권을 이동하면 다른 스레드에서 사용할 수 없고, 참조를 전달하려고 하면 수명(lifetime) 문제로 컴파일 오류가 발생합니다. 실제로는 여러 스레드가 같은 설정 값을 읽거나, 공유 데이터를 참조해야 하는 상황이 많습니다. 예를 들어 웹 서버에서 모든 워커 스레드가 동일한 설정 파일을 읽어야 하거나, 여러 스레드가 같은 캐시 데이터를

Rust 기초: Weak로 순환 참조 끊기

Rust 기초: Weak로 순환 참조 끊기

Rc로 노드를 만들어 서로 연결하다 보면 이상한 일을 겪게 됩니다. 분명 스코프를 벗어났는데 소멸자가 실행되지 않는 거죠. Rust는 메모리 안전한 언어인데 어떻게 누수가 나느냐고요? 😱 직접 확인해 보겠습니다. 서로를 짝으로 가리키는 노드 둘을 만들고, 해제될 때 메시지를 찍도록 Drop을 구현했습니다. "해제됨"이 한 번도 찍히지 않았습니다. 두 노드 모두 메모리에 그대로 남아 있는 거예요. 강한 참조끼리 물면 카운트가 0이 되지 않습니다 원인은 참조 카운트에 있습니다. Rc는 자기를 가리키는 강한 참조(strong refer

Rust 기초: Rc로 단일 스레드에서 데이터 공유하기

Rust 기초: Rc로 단일 스레드에서 데이터 공유하기

Rust의 소유권 시스템은 "한 번에 하나의 소유자만 존재할 수 있다"는 명확한 규칙을 가지고 있습니다. 대부분의 경우 이 규칙만으로 충분하지만, 때로는 여러 부분에서 같은 데이터를 소유해야 하는 상황이 있습니다. 예를 들어 그래프 자료구조에서 여러 노드가 같은 노드를 가리켜야 할 수 있습니다. 단일 스레드 환경에서 이런 공유 소유권이 필요할 때 Rc(Reference Counted)를 사용합니다. Rc는 참조 카운팅을 통해 여러 소유자가 같은 데이터를 공유할 수 있게 해주는 스마트 포인터입니다. 데이터를 가리키는 참조가 몇 개인지

Vim 완벽 가이드: 키보드만으로 코딩하기

Vim 완벽 가이드: 키보드만으로 코딩하기

VS Code나 IntelliJ를 잘 쓰고 있었는데, 어느 날 서버에 SSH로 접속해서 파일을 수정할 일이 생겼습니다. vim config.yaml을 입력했더니 화면이 바뀌면서 커서가 깜빡이고 있어요. 키보드를 누르는데 글자가 입력이 안 됩니다. 아니, 입력되는 것 같기도 한데 이상한 동작을 하고 있어요. 끄고 싶은데 Ctrl+C도 안 먹히고, Ctrl+W를 눌렀더니 창이 닫히는 대신 뭔가 다른 일이 벌어집니다. 이 상황, 개발자라면 한 번쯤 겪어보셨을 거예요. 😅 "Vim 종료하는 법"은 Stack Overflow에서 200만

Rust 기초: RefCell로 불변 참조에서 값 바꾸기

Rust 기초: RefCell로 불변 참조에서 값 바꾸기

구조체 안에 호출 횟수를 세는 필드 하나 두려다가 컴파일러에게 막혀 보신 적 있으신가요? 로그를 찍는 김에 카운터도 올리고 싶을 뿐인데 말이죠. 컴파일러 제안대로 &mut self로 바꾸면 되긴 합니다. 그런데 그러면 log를 부르는 쪽도 전부 가변 참조를 들고 있어야 하고, 여러 곳에서 로거를 공유하던 구조가 통째로 무너집니다. 겨우 카운터 하나 때문에요. 😅 소유권과 빌림 규칙이 원래 그렇습니다. 불변 참조가 하나라도 살아 있으면 값을 바꿀 수 없어요. 그런데 이 규칙을 지키면서도 값을 바꿀 방법이 있습니다. 검사 시점을 컴파

Rust Box::pin은 언제 사용할까?

Rust Box::pin은 언제 사용할까?

Rust 비동기 코드를 읽다 보면 이런 타입을 마주칠 때가 있습니다. 처음 보면 부담스럽습니다. Box도 알고, Future도 대충 알겠는데 중간에 Pin이 끼어들면서 갑자기 어려워 보이죠. 게다가 예제 코드에서는 Box::new()가 아니라 Box::pin()을 쓰기도 합니다. 이건 단순히 future를 박스에 넣는 코드일까요? 아니면 뭔가 더 특별한 일을 하는 걸까요? 이번 글에서는 Box::pin이 언제 필요한지 차근차근 살펴보겠습니다. Box 자체가 아직 익숙하지 않다면 Box로 힙에 데이터 저장하기를 먼저 읽어보시면 좋습니

Rust 기초: Box로 힙에 데이터 저장하기

Rust 기초: Box로 힙에 데이터 저장하기

Rust에서 대부분의 값은 스택에 저장됩니다. 스택은 빠르고 효율적이지만 컴파일 시점에 크기를 알 수 있는 데이터만 다룰 수 있다는 제약이 있죠. 그런데 프로그래밍을 하다 보면 크기를 미리 알 수 없는 데이터를 다루거나 큰 데이터를 복사 없이 전달하고 싶을 때가 있습니다. 이럴 때 쓰는 게 바로 Box입니다. Box는 Rust에서 가장 단순하면서도 자주 쓰이는 스마트 포인터로, 데이터를 힙 메모리에 저장하고 그 포인터를 스택에 두는 방식으로 동작해요. 이 글에서는 Box가 무엇이고 언제 필요한지, 실전에서 어떻게 활용하는지 예제와

Model Context Protocol: AI 애플리케이션의 통신 표준

Model Context Protocol: AI 애플리케이션의 통신 표준

Chat GPT와 같은 대형 언어 모델(LLM)이 급속도로 발전하면서 이를 활용한 다양한 AI 에이전트 및 확장 서비스들이 등장하고 있습니다. 하지만 LLM은 학습된 시점의 데이터에 갇혀 실시간 정보에 접근하거나 외부 시스템과 상호작용하는 데 한계가 있습니다. 뿐만 아니라, 비지니스 도메인에 맞는 문맥(Context)에서 AI 애플리케이션이 작동하도록 하는 것은 여전히 큰 도전입니다. 이러한 LLM의 한계를 극복하고 AI의 잠재력을 최대한 발휘하기 위해 등장한 것이 바로 Model Context Protocol, 줄여서 MCP입니다

Rust 비동기 런타임: Tokio 크레이트 사용법

Rust 비동기 런타임: Tokio 크레이트 사용법

Rust로 네트워크 서버를 만들거나 여러 작업을 동시에 처리해야 할 때, 어디서부터 시작해야 할지 막막한 적이 있으신가요? Rust는 async/await 문법을 언어 차원에서 지원하지만, 이걸 실제로 실행하려면 비동기 런타임이 필요합니다. 그리고 Rust 생태계에서 가장 널리 쓰이는 비동기 런타임이 바로 Tokio입니다. 이번 글에서는 Tokio가 무엇이고, 왜 필요한지부터 시작해서 실제로 비동기 코드를 작성하고 실행하는 방법까지 차근차근 다뤄보겠습니다. 비동기 프로그래밍이 필요한 이유 웹 서버를 하나 만든다고 생각해볼까요? 클라

Rust 기초: Deref 트레이트와 역참조 강제(Deref Coercion)

Rust 기초: Deref 트레이트와 역참조 강제(Deref Coercion)

Rust로 코드를 작성하다 보면 신기한 장면을 목격할 때가 있습니다. Box<String>을 넘겼는데 &str을 기대하는 함수가 아무 문제없이 호출된다거나, Rc<Vec<i32>>에 대고 .iter()를 바로 호출할 수 있다거나 하는 것들이죠. 분명 타입이 다른데 컴파일러가 알아서 잘 처리해줍니다. 이런 마법 같은 일이 가능한 건 Rust의 Deref 트레이트와 역참조 강제(Deref coercion)라는 메커니즘 덕분입니다. 이 글에서는 역참조가 무엇인지부터 시작해서 Deref 트레이트를 직접 구현해보고, 역참조 강제가 실제로 어

달레 블로그의 SEO 비법 🎯

달레 블로그의 SEO 비법 🎯

달레 블로그의 SEO 비법 🎯 "달레님 블로그 글은 어떻게 항상 구글 검색 맨 위에 나오나요?" 참 자주 여쭤 보시는 질문인데, 사실 저도 깜짝 놀랄 때가 있습니다. "어라? 어떻게 내 글이 공식 문서 보다도 위에 있지?" 하는 순간이 있거든요. 😅 많은 분들이 제게 숨겨진 SEO(검색 엔진 최적화) 비법이 있을 거라 생각하시지만, 사실 제 블로그는 아주 기본적인 SEO 공식조차 거의 따르지 않고 있습니다. SEO 전문가들이 말하는 Best Practice인 사이트맵이나 RSS 피드도 없고, 키워드 검색을 위한 메타 태그도 크게

Rust Future란 무엇인가: async fn이 바로 실행되지 않는 이유

Rust Future란 무엇인가: async fn이 바로 실행되지 않는 이유

Rust에서 비동기 코드를 처음 보면 async와 await는 꽤 익숙해 보입니다. JavaScript나 Python을 써보셨다면 더 그렇죠. 그런데 막상 Rust에서 async fn을 호출해보면 살짝 당황스러운 지점이 나옵니다. 함수를 호출했는데 실행이 바로 시작되지 않습니다. 반환값도 우리가 기대한 값이 아니라 Future입니다. 그리고 .await를 붙이지 않으면 아무 일도 일어나지 않는 것처럼 보이죠. 🤔 Tokio 입문 글에서도 이 차이를 잠깐 다뤘는데요. 이번 글에서는 Tokio 같은 런타임을 쓰기 전에, Rust의 F

Rust 기초: From과 Into 트레이트

Rust 기초: From과 Into 트레이트

자료형 간의 명시적이고 안전한 데이터 변환은 Rust의 중요한 철학 중 하나입니다. Rust는 From과 Into라는 표준 트레이트을 제공하여 데이터 변환을 안전하고 명확하게 할 수 있도록 돕는데요. 이 글에서는 이 두 트레이트의 관계와 차이점, 그리고 활용법을 살펴보겠습니다. From 트레이트란? From 트레이트은 다른 자료형부터(from) 현재 자료형으로 변환하는 방법을 정의할 때 사용합니다. From 트레이트의 from() 메서드는 다른 제네릭(generic) 타입을 인자로 받고 자신의 타입을 반환합니다. 예를 들어, Rus

Rust blanket impl: 여러 타입에 트레이트를 한 번에 구현하기

Rust blanket impl: 여러 타입에 트레이트를 한 번에 구현하기

Rust 표준 라이브러리 문서를 읽다 보면 이런 구현을 자주 마주칩니다. 처음 보면 조금 낯섭니다. impl Into<String> for MyType처럼 특정 타입에 트레이트를 구현하는 건 이해가 되는데, 여기서는 impl<T, U>로 모든 타입을 열어두고 있죠. "모든 T에 대해 Into<U>를 구현한다"는 말처럼 보이는데, 정말 그래도 되는 걸까요? 이런 구현을 보통 blanket implementation, 줄여서 blanket impl이라고 부릅니다. 한국어로는 "포괄 구현" 정도로 옮길 수 있지만, Rust 문맥에서는 원

Nuxt 4: Vue로 풀스택 웹 앱 만들기

Nuxt 4: Vue로 풀스택 웹 앱 만들기

Vue 3 글에서 할 일 목록 앱을 만들어 봤는데요. 그 앱은 데이터를 브라우저의 localStorage에 저장했기 때문에, 다른 기기에서 열면 목록이 텅 비어 있습니다. 데이터를 서버에 두려면 API 서버를 따로 만들고, 페이지가 늘어나면 라우터를 붙이고, 검색 엔진에 노출하려면 서버 렌더링까지 고민해야 하죠. 😅 Nuxt는 이 모든 걸 하나의 프로젝트에서 해결해 주는 Vue 기반의 풀스택 프레임워크입니다. React에 Next.js가 있다면 Vue에는 Nuxt가 있는 셈인데요. 2025년 7월 15일에는 디렉터리 구조와 데이터

Rust 기초: Copy와 Clone 트레이트 이해하기

Rust 기초: Copy와 Clone 트레이트 이해하기

Rust에서 변수를 다른 변수에 할당하면 값이 복사될 때도 있고 소유권이 이동할 때도 있습니다. 정수는 let y = x; 해도 x를 계속 쓸 수 있는데, String은 같은 걸 하면 원래 변수를 못 쓰게 되죠. 이 차이를 결정하는 게 바로 Copy와 Clone 트레이트입니다. 둘 다 "값을 복사한다"는 점은 같지만, 동작 방식과 쓰임새가 꽤 다릅니다. 이 글에서는 Copy와 Clone이 각각 무엇이고, 어떤 관계이며, 실제로 어떻게 쓰는지 알아보겠습니다. 소유권과 빌림에서 다룬 이동(move)과 복사(copy) 개념을 알고 있으면

Rust 기초: 수명(Lifetime)으로 참조의 유효 범위 관리하기

Rust 기초: 수명(Lifetime)으로 참조의 유효 범위 관리하기

Rust로 코드를 짜다 보면 어김없이 만나게 되는 오류가 있습니다. 분명히 변수를 선언하고 참조했을 뿐인데 "충분히 오래 살지 못한다"는 야박한 평가를 받는데요. 이 오류는 Rust의 또 다른 핵심 개념인 수명(lifetime)과 관련이 있습니다. 수명은 모든 참조가 가지는 속성이고, 컴파일러의 빌림 검사기(borrow checker)가 메모리 안전성을 보장하는 데 쓰는 도구이기도 합니다. 이 글에서는 수명이 무엇인지, 컴파일러가 어떻게 검증하는지, 우리가 직접 표기해야 하는 순간은 언제인지 알아보겠습니다. 기본적인 소유권과 빌림

Better Auth로 TypeScript 인증 시스템 구축하기

Better Auth로 TypeScript 인증 시스템 구축하기

웹 애플리케이션을 만들 때 인증은 거의 빠지지 않는 기능인데요. 직접 구현하자니 보안 허점이 걱정되고 기존 라이브러리를 쓰자니 특정 프레임워크에 묶이거나 설정이 복잡한 경우가 많습니다. Better Auth는 이런 고민에서 출발한 TypeScript 네이티브 인증 라이브러리입니다. 2026년 7월에는 Vercel이 Better Auth를 개발하는 회사를 인수하면서 앞으로의 방향에도 관심이 쏠렸습니다. 프레임워크를 가리지 않고 플러그인으로 기능을 확장하고 데이터베이스 스키마까지 직접 관리해 주는 게 특징인데요. 이 글에서는 Bette

GitHub Personal Access Token 제대로 이해하기: 클래식과 파인그레인드

GitHub Personal Access Token 제대로 이해하기: 클래식과 파인그레인드

GitHub에 인증할 일이 생기면 가장 먼저 손이 가는 게 개인 액세스 토큰(Personal Access Token, 이하 PAT)입니다. private 저장소를 클론하거나, API를 호출하거나, 스크립트로 이슈를 다룰 때 토큰 하나면 되니까요. 그런데 막상 발급 화면에 가면 "Fine-grained tokens"와 "Tokens (classic)" 두 가지가 있고, 스코프와 권한 목록이 빽빽하게 펼쳐져서 일단 아무거나 골라 repo 전체에 체크하고 넘어가기 십상이에요. 이번 글에서는 이 PAT를 제대로 짚어보겠습니다. PAT는 어

Rust 기초: 트레이트(Trait) 사용법

Rust 기초: 트레이트(Trait) 사용법

구조체와 열거형으로 데이터의 형태를 정의하는 방법을 배웠는데요. 그런데 서로 다른 타입이 같은 동작을 공유해야 하는 상황이 자주 생깁니다. 원과 직사각형은 완전히 다른 구조의 데이터이지만 둘 다 "넓이를 구한다"는 동작은 가지고 있잖아요. Rust에서는 이런 공통 동작을 트레이트(Trait)로 정의합니다. 이 글에서는 트레이트가 무엇이고 어떻게 정의하고 구현하는지 예제와 함께 살펴보겠습니다. 트레이트란? 트레이트(Trait)는 여러 타입이 공통으로 가져야 하는 동작(behavior)을 정의하는 방법입니다. Java나 TypeScri

Discord