# Go vs. Rust vs. Zig에 대한 생각

> Clean Markdown view of GeekNews topic #24861. Use the original source for factual precision when an external source URL is present.

## Metadata

- GeekNews HTML: [https://news.hada.io/topic?id=24861](https://news.hada.io/topic?id=24861)
- GeekNews Markdown: [https://news.hada.io/topic/24861.md](https://news.hada.io/topic/24861.md)
- Type: GN+
- Author: [neo](https://news.hada.io/@neo)
- Published: 2025-12-06T03:34:09+09:00
- Updated: 2025-12-06T03:34:09+09:00
- Original source: [sinclairtarget.com](https://sinclairtarget.com/blog/2025/08/thoughts-on-go-vs.-rust-vs.-zig/)
- Points: 30
- Comments: 1

## Summary

서로 다른 언어의 문법보다 흥미로운 것은, 그 언어가 어떤 **가치를 구현하려는가**입니다. Go는 협업과 단순함을 위해 기능을 최소화하고, Rust는 복잡한 타입 시스템으로 **메모리 안전성**을 보장하며, Zig는 수동 제어를 통해 데이터 중심 설계를 실험합니다. 세 언어의 상반된 선택은 결국 “좋은 소프트웨어란 무엇인가”에 대한 각자의 답변을 보여줍니다. 개발자가 공감하는 철학이 곧 언어 선택의 기준이 되는 이유입니다.

## Topic Body

- 세 언어의 **철학과 가치관의 차이**를 중심으로, 각 언어가 어떤 문제를 해결하려는지 비교  
- **Go**는 단순성과 안정성을 중시하며, 기능을 최소화해 협업과 유지보수를 쉽게 만드는 언어로 설명됨  
- **Rust**는 안전성과 성능을 동시에 추구하며, 복잡한 타입 시스템과 트레이트 구조로 **메모리 안전성**을 보장  
- **Zig**는 수동 메모리 관리와 **데이터 중심 설계**를 통해 개발자에게 완전한 제어권을 부여하는 실험적 언어로 묘사됨  
- 세 언어의 상반된 접근은 **프로그래밍 언어가 구현하는 가치 체계**를 드러내며, 개발자가 어떤 철학에 공감하느냐가 선택의 기준이 됨  

---

### 언어 비교의 관점
- 작성자는 직장에서 사용하는 언어가 아닌, **새로운 언어 실험을 통해 각 언어의 가치 체계**를 이해하려 함  
- 단순히 기능 목록을 비교하기보다, **언어가 어떤 트레이드오프를 선택했는가**가 중요하다고 강조  
- Go, Rust, Zig는 기능적으로 겹치는 부분이 많지만, **설계자가 중시한 가치**가 다름  
- 각 언어의 철학을 파악함으로써, 어떤 환경과 목적에 적합한지 판단 가능  

### Go — 단순함과 협업 중심의 언어
- Go는 **미니멀리즘**으로 구별되며, “머릿속에 전체 언어를 담을 수 있다”는 특징을 가짐  
  - 제네릭은 12년 만에 추가되었고, **태그드 유니언**이나 **에러 처리 문법 설탕** 같은 기능은 여전히 없음  
- 기능 추가에 매우 신중하여, **보일러플레이트 코드**가 많지만 **언어의 안정성과 가독성**이 높음  
- Go의 **슬라이스(slice)** 는 Rust의 `Vec&lt;T&gt;`나 Zig의 `ArrayList` 기능을 포괄하며, 메모리 위치를 런타임이 자동 관리  
- C++의 복잡성과 컴파일 지연에 대한 불만에서 출발해, **단순하고 빠른 컴파일**을 목표로 설계  
- **기업 환경에서의 협업 효율성**을 중시하며, 복잡한 기능보다 명료한 코드와 일관성을 우선  

### Rust — 복잡하지만 강력한 안전성과 성능
- Rust는 **“제로 비용 추상화”** 를 내세우며, 다양한 개념이 결합된 **맥시멀리스트 언어**  
- 학습 난이도가 높은 이유는 **개념 밀도**가 높기 때문이며, 복잡한 타입 시스템과 트레이트 구조가 존재  
- Rust의 핵심 목표는 **성능과 메모리 안전성**의 양립  
  - **UB(Undefined Behavior)** 를 방지하기 위해 컴파일 타임에 검증 수행  
  - 잘못된 포인터 참조나 이중 해제 등으로 인한 **예측 불가능한 동작**을 차단  
- 컴파일러가 코드의 런타임 동작을 이해할 수 있도록, 개발자는 **명시적으로 타입과 트레이트를 정의**해야 함  
- 이러한 구조 덕분에 **타인의 코드에 대한 신뢰성**이 높고, **라이브러리 생태계**가 활발하게 유지됨  

### Zig — 완전한 제어와 데이터 중심 설계
- Zig는 세 언어 중 가장 **신생 언어**로, 버전 0.14 단계이며 표준 라이브러리 문서화가 거의 없음  
- **수동 메모리 관리**를 채택해, 개발자가 직접 `alloc()`을 호출하고 **할당자(allocator)** 를 선택해야 함  
- Rust나 Go와 달리, **전역 변수 생성이 간단**하며, 런타임에서 “illegal behavior”를 감지해 프로그램을 중단  
  - 빌드 시 선택 가능한 **4가지 릴리스 모드**로 성능과 안정성의 균형 조정 가능  
- **객체지향 프로그래밍(OOP)** 기능을 의도적으로 배제  
  - **private 필드**나 **동적 디스패치**가 없으며, `std.mem.Allocator`조차 인터페이스로 구현되지 않음  
  - 대신 **데이터 중심 설계(data-oriented design)** 를 지향  
- 메모리 관리 또한 **RAII 방식의 세밀한 객체 단위 관리 대신**, 큰 메모리 블록을 주기적으로 할당·해제하는 구조를 권장  
- Zig는 **자유롭고 반체제적인 성향**의 언어로 묘사되며, **OOP적 사고를 제거하고 개발자 주도 제어를 극대화**  
- 현재 팀은 **모든 의존성 재작성 작업**에 집중 중이며, 안정 버전(1.0)은 아직 미정  

### 결론 — 언어가 드러내는 가치의 차이
- Go는 **협업과 단순성**, Rust는 **안전성과 성능**, Zig는 **자유와 제어권**을 중심 가치로 삼음  
- 세 언어의 차이는 단순한 기능 비교가 아니라, **소프트웨어 개발에 대한 철학적 선택**을 반영  
- 개발자는 자신이 **어떤 가치에 공감하는가**에 따라 언어를 선택하게 됨

## Comments



### Comment 47280

- Author: neo
- Created: 2025-12-06T03:34:09+09:00
- Points: 1

###### [Hacker News 의견](https://news.ycombinator.com/item?id=46153466) 
- Rust에서 **mutable global variable**을 만드는 건 어렵지 않음  
  단지 `unsafe`나 동기화를 제공하는 스마트 포인터를 써야 함  
  Rust는 기본적으로 **re-entrant**하며 컴파일 타임에 스레드 안전성을 보장하기 때문임  
  만약 정적 스레드 안전성을 신경 쓰지 않는다면 Zig나 C처럼 쉽게 만들 수 있음  
  차이는 Rust는 코드의 런타임 동작에 대해 더 많은 **보증 도구**를 제공한다는 점임
  - 여러 해 Rust를 써본 입장에서, mutable global variable은 “할 수 있다고 해서 해야 하는 건 아니다”의 전형적인 예라고 생각함  
    다른 언어로 돌아가서 이런 걸 아무렇지 않게 쓰는 걸 보면 **안전성** 측면에서 미친 짓처럼 느껴짐
  - “trivial하다, 단지 ~가 필요하다”는 식의 표현은 C++이나 Perl, Haskell에서도 들었던 이야기임  
    하지만 이런 식의 “단순한 일”들이 쌓이면 결코 단순하지 않게 됨  
    Rust는 이미 그 선을 넘었고, 이제는 결코 **trivial하지 않음**
  - Rust 컴파일러가 스레드 간 **race condition**을 컴파일 타임에 잡아주는지 궁금함  
    그렇다면 C보다 매력적일 것 같음  
    두 변수가 항상 함께 잠겨야 하는 상황에서는 어떻게 처리하는지도 알고 싶음
  - 내가 언어를 만든다면 mutable global variable은 아예 **금지**시킬 것임  
    디버깅하다 보면 결국 문제의 근원은 항상 그쪽이었음

- Rust의 개념 밀도를 지적한 글에 대해, 실제로는 그 중 **5%만 알아도 생산적**으로 쓸 수 있다고 생각함  
  12년 넘게 Rust를 써왔지만 `#[fundamental]` 같은 건 한 번도 쓸 일이 없었음  
  Rust에서도 **arena allocation**을 할 수 있고, allocator 개념도 존재함  
  기본 allocator가 있을 뿐이며, 보통 `Box::new` 같은 명시적 힙 할당을 사용함  
  mutable global은 `static FOO: Mutex&lt;T&gt; = Mutex::new(...)`처럼 만들 수 있고, **메모리 안전성**을 위해 mutex가 필요함  
  Rust의 타입 시스템은 메모리 안전성뿐 아니라 코드의 의미적 안전성까지 보장하도록 설계되어 있음
  - 하지만 다른 개발자가 다른 **5~10%의 개념**을 쓸 수 있기 때문에, 협업 시 결국 더 많은 개념을 배워야 함  
    C에서는 이런 복잡성이 적음  
    **복잡도**는 결국 중요한 문제임
  - “Rust도 arena allocation이 가능하다”는 말은 맞지만, 대부분의 Rust/Go 코드는 작은 단위의 **다수의 할당**을 기본 경로로 가짐  
    단순히 가능 여부의 문제가 아니라 기본적인 프로그래밍 스타일의 차이에 대한 이야기임
  - Rust에서 allocator가 타입이라면, m:n 스레드 모델에서 각 요청마다 **별도의 arena**를 줄 수 있는지도 궁금함
  - Rust의 allocator가 **전역(global)** 인지, 모든 힙 할당이 같은 allocator를 사용하는지도 질문함
  - Casey Muratori의 [batch allocation 영상](https://www.youtube.com/watch?v=xt1KNDmOYqA)을 언급하며, 일부 개발자들이 이를 잘못 이해하고 Rust의 RAII를 비판한다고 지적함  
    Zig Software Foundation이 Asahi Lina의 Rust 관련 발언을 잘못 인용한 사례도 있었음  
    Zig가 다른 언어를 깎아내리는 **마케팅 태도**는 별로 마음에 들지 않음

- Zig가 마음에 드는 이유는 메모리 고갈을 **우아하게 처리**할 수 있는 언어이기 때문임  
  모든 할당이 실패 가능(fallible)하다고 가정하고, 명시적으로 처리해야 함  
  스택 공간도 마법처럼 다루지 않고, 컴파일러가 호출 그래프를 분석해 최대 크기를 추론함  
  임베디드 환경에서 이런 **자원 중심 설계**는 필수적임
  - 하지만 Linux처럼 **overcommit**을 사용하는 OS에서는 실제로 할당 실패가 발생하지 않음  
    언어 차원의 처리로는 해결되지 않음
  - Zig가 존재해야 하는 이유가 Rust가 이미 있는데 무엇이냐는 질문에, 차라리 “C가 있는데 왜 Zig인가?”를 묻겠음  
    결국 수동 메모리 관리라는 같은 문제를 안고 있음  
    그렇다면 **GC 언어**를 쓰는 게 낫다고 생각함
  - 재귀나 함수 포인터 호출이 있을 때 Zig의 **스택 크기 추론**이 어떻게 작동하는지 궁금함
  - Zig가 처음은 아니며, 1958년 JOVIAL 이후의 **시스템 언어 역사**를 살펴볼 필요가 있음
  - Rust에서도 pre-allocation을 잘 처리할 수 있음  
    다만 Rust의 표준 라이브러리는 OOM 시 panic을 사용하기 때문에, **no-std 환경**에서 임베디드 개발을 지원하는 생태계가 따로 있음

- Go의 **slice**는 Rust의 `Vec&lt;T&gt;`와 다름  
  `append()`는 새로운 slice를 반환하며, 기존 메모리를 공유할 수도 있고 아닐 수도 있음  
  메모리를 줄이는 방법도 없고, `append(s, ...)`만 쓰면 새 slice를 무시하게 됨  
  Go는 “내가 말한 대로 해라”는 태도이고, Rust는 “내가 말한 대로 했는지 검증하라”는 태도임  
  즉, Go는 단순함을 위해 실수를 허용하고, Rust는 복잡해지더라도 **실수를 줄이는 방향**을 택함
  - 실제로는 [slices.Clip](https://pkg.go.dev/slices#Clip)으로 메모리를 줄일 수 있음  
    또한 `append(s, ...)`만 쓰면 컴파일 오류가 나므로, 원문은 약간 **부정확한 주장**임  
    Go는 기능 추가 시 복잡도 증가를 신중히 따지는 언어임
  - “append(s, …)”는 컴파일조차 되지 않기 때문에 초보자가 그런 실수를 할 수 없다고 생각함
  - Go에 제네릭이 생겼는데도 **List[T]** 같은 타입이 널리 쓰이지 않는 게 흥미로움  
    아마 growable list를 직접 넘길 일이 많지 않기 때문일 것임
  - Go는 명세와 문서에 대부분의 **함정(foot gun)** 이 명확히 적혀 있음  
    단순히 문서를 안 읽고 놀라워하는 경우가 많음

- C/C++의 **UB(Undefined Behavior)** 를 런타임 검사로 잡는 건 현실적으로 어렵다고 생각함  
  Android도 sanitizer를 모든 커밋에 적용했지만, Rust로 전환하고 나서야 **익스플로잇이 줄어듦**
  - Android의 sanitizer 관련 주장에 대한 **출처**를 요청함

- 언어 비교 글이 각 언어의 **강점과 약점**을 솔직하게 다뤄서 좋았음  
  다만 Raku가 언급되지 않아 아쉬움  
  내 생각엔 C–Zig–C++–Rust–Go가 저수준 언어의 연속선이라면, 고수준 쪽은 Julia–R–Python–Lua–JS–PHP–Raku–WL로 이어짐
  - WL이 무엇인지 질문함
  - Raku는 **표현력이 풍부한 범용 언어**로, 다중 디스패치·역할(roles)·점진적 타입·게으른 평가·강력한 정규식 시스템을 내장함  
    문법 정의를 언어 차원에서 지원해 DSL이나 로그 파싱이 쉬움  
    VM 기반이라 성능은 낮지만, **문제 구조를 직접 표현**하기에 적합함  
    Perl의 후계로서 유연하고 일관된 언어를 지향함

- Rust에서 함수가 포인터를 반환하면 힙 할당이 자동으로 일어난다고 생각하는 건 오해임  
  지역 변수는 스택에 있고, 반환 시 사라지므로 포인터는 무효화됨  
  Rust는 안전 모드에서는 포인터 역참조가 불가능하고, unsafe 모드에서는 개발자가 **유효성 보장 책임**을 짐  
  아마도 `Box::new`를 “암묵적 할당”으로 착각한 듯함
  - Go의 **escape analysis**와 Rust의 명시적 힙 할당을 혼동하는 건 이해하기 어려움  
    이는 개념을 잘못 이해했거나 의도적으로 **오도**하는 것처럼 보임

- Go의 가장 큰 장점은 **간단한 동시성 모델**임  
  goroutine 덕분에 쉽게 병렬 코드를 작성할 수 있음
  - Go의 장점 중 하나는 **코드 일관성** 덕분에 대규모 코드베이스를 탐색하기 쉽다는 점임  
    인터페이스 구현을 찾는 건 어렵지만, 가독성이 높아 팀 협업에 유리함
  - Rob Pike의 [“Concurrency is not Parallelism”](https://youtu.be/oV9rvDllKEg) 강연이 Go의 동시성 철학을 잘 설명함  
    **colored function**이 없고, 채널 기반 통신이 단순해 **정확한 동시성 코드**를 빠르게 작성할 수 있음
  - 하지만 **Structured Concurrency**가 더 쉬운 모델이라고 생각함  
    관련 글: [Structured Concurrency or Go Statement Considered Harmful](https://vorpus.org/blog/notes-on-structured-concurrency-or-go-statement-considered-harmful/)
  - Zig의 새로운 `std.Io` 인터페이스는 Go의 동시성 모델과 유사함  
    `go` 키워드는 `std.Io.async`, 채널은 `std.Io.Queue`, `select`는 `std.Io.select`로 대응됨
  - **Erlang** 개발자라면 Go의 동시성 모델이 가장 쉽다는 주장에 동의하지 않을 것임

- 내가 원하는 건 **Go의 단순함**에 Rust의 **결과/에러/열거형 처리**와 더 나은 제네릭을 결합한 언어임
  - 나도 동의함. GC가 있으면서 더 강력한 타입 시스템을 가진 네이티브 언어의 **시장 수요**가 큼  
    OCaml, D, Swift, Nim, Crystal 등을 봤지만 아직 시장을 장악한 언어는 없음
  - 최신 OCaml은 매우 강력한 **동시성 모델**을 갖추었고, 성능도 Go와 경쟁 가능하다고 들음
  - [Borgo 언어](https://github.com/borgo-lang/borgo)는 그런 시도를 했지만 중단됨  
    대신 **Gleam**을 살펴볼 만함
  - Go의 [error proposal](https://github.com/golang/go/issues/71528)이 흥미로웠음  
    이런 반복되는 문제를 해결할 수 있는 개선이 나오길 기대함  
    제네릭은 여전히 어려운 과제일 것임
  - 가장 가까운 대안은 **C#** 이지만, 여전히 **OOP 중심 언어**임

- 글의 전반적인 톤이 신입 개발자의 **열정과 호기심**이 느껴져 좋았음  
  Go의 제네릭 부재는 단순한 미니멀리즘이 아니라, **트레이드오프 고민의 결과**였다고 생각함  
  Rust의 **lifetime**은 많은 사람에게 가장 큰 난관이었고, 언어의 혁신성은 기존 개념의 조합에 있음  
  Zig의 수동 메모리 관리는 OOP 배제보다는 **Data-Oriented Design(DOD)** 철학에 기반함  
  관련 강연: [Andrew의 DOD 발표](https://www.youtube.com/watch?v=IroPQ150F6c)
  - Russ Cox가 2009년에 [“The Generic Dilemma”](https://research.swtch.com/generic) 글에서 제시한 문제처럼,  
    “느린 프로그래머, 느린 컴파일러, 느린 실행 중 무엇을 택할 것인가”가 핵심이었음  
    Go 팀은 결국 이를 만족스럽게 해결하는 **절충안**을 찾은 것으로 보임
