러스트의 안전 장치 중 마음에 든 것
by
gg582 · 2026-09-22 05:48:49 · 63 views · 2 min read
Table of contents
Rust의 이터레이터 소유권과 런타임 안전장치
취미로 수학 문제를 푸는 김에 러스트로 짜 보면 연습이 될 것 같아 공부하고 있는 중에, 러스트의 아주 마음에 드는 안전장치를 서술한다.
우선 틀린 코드를 보자.
use std::io;
fn res(n: u64) -> f64 {
assert!(n >= 2, "n >= 2 assertion failed.");
let n = n as f64;
1.5 - (2.0 * n + 1.0) / (n * n + n)
}
fn main() {
let mut input = String::new();
io::stdin().read_line(&mut input).unwrap();
let mut iter = input.split_whitespace();
// by_ref()로 빌려오면 컴파일 에러는 안 나지만...
if iter.by_ref().count() == 1 {
// 이미 count()가 iter를 끝까지 순회해서 소진시켰으므로
// next()는 None을 반환하고 unwrap()에서 panic 발생
let n: u64 = iter.next().unwrap().parse().unwrap();
println!("{}", res(n));
}
}
C++이라면 이터레이터가 순회를 마쳐 end()에 도달한 상태에서 이를 한 칸 더 전진시키거나 접근할 때 정의되지 않은 동작(UB)이 발생하여 메모리 오염으로 이어지거나 세그멘테이션 오류를 발생시킨다.
C++26 등 안전한 문법들을 사용하면 러스트와 같이 방어적으로 프로그래밍할 수 있으나, 강제되는 사항도 아닐뿐더러 하위 호환성을 유지하다 보니 여전히 위험한 문법을 사용 가능해서 수렁에 빠지기 좋다.
그렇다고 무조건 러스트로 재작성하자는 건 아니다. C++에서는 C++26 등의 최신 문법을 의식하며 작성하는 편이 낫다는 것이다.
반면 Rust에서는 이터레이터가 소진되면 안전하게 None을 반환하고, 이를 무작정 unwrap()할 경우 런타임에 명확한 패닉 메시지를 출력하며 안전하게 종료된다.
만약 iter.by_ref() 없이 iter.count()를 불렀다면, count()가 이터레이터를 소유하기 때문에 이후 iter.next()를 호출하는 시점에 컴파일러가 소유권 이동을 금지하여 컴파일 오류를 낸다.
주인이 명확한 물건을 가져가 쓰는 것은 좋지 않습니다. 전략적 물자 이동과 도둑질은 다르거든요.
벡터를 쓰는 방식
use std::io;
fn res(n: u64) -> f64 {
assert!(n >= 2, "n >= 2 assertion failed.");
let n = n as f64;
1.5 - (2.0 * n + 1.0) / (n * n + n)
}
fn main() {
let mut input = String::new();
io::stdin().read_line(&mut input).unwrap();
let tokens: Vec<&str> = input.split_whitespace().collect();
if tokens.len() == 1 {
let n: u64 = tokens[0].parse().unwrap();
println!("{}", res(n));
}
}
이터레이터 상태대로 두지 않고, 입력 스트링을 공백 기준으로 분리한 뒤 collect()를 통해 벡터 타입에 모아 주자.
이러면 인덱싱으로 필요한 tokens[0]을 파싱해 부호 없는 64비트 정수형으로 쓰면 된다.
길이가 1인 상태에서 잘못하여 tokens[1]에 접근하더라도, Rust와 같은 최신 언어는 경계 검사를 수행하여 메모리 영역 침범 대신 패닉을 발생시키고 프로그램을 안전하게 종료한다.
한 가지 생각
C/C++은 여전히 사람의 언어랑 닮은 부분이 있어서, 맥락을 파악하지 못하면 실수하기 쉽다. 반면 러스트는 보다 공업적이고 문제를 미연에 차단하기 때문에, 운치는 없지만 프로덕션에서 보다 안전하다.
하지만 이런 구문은 맥락이니 운치를 떠나서 사람 간의 대화에서도 중요해 보인다.
맥락을 납작하게 하다가 싸우기만 하지 말고, 맥락을 풍부하게 해서 서로 이해할 수 있게 하는 게 더 성숙한 대화가 아닐까요?