Rust 에러 E0658: use of unstable library feature (불안정한 기능 사용)
E0658은 Rust에 있긴 하지만 아직 완성되지 않은 것을 써서, 안정판(stable) Rust가 허락하지 않는다는 뜻이에요. 보통은 표준 라이브러리 문서나 블로그 글에서 찾은 .intersperse()나 .try_collect() 같은 메서드, 또는 try { ... } 같은 문법이에요. 내 코드가 틀린 것도, 내 컴퓨터에 뭔가 고장 난 것도 아니에요. nightly 컴파일러에서만 동작하는 기능에 손을 뻗었을 뿐이에요. 거의 언제나 같은 일을 한 줄로 해내는 안정판 방법이 있어요. 이 페이지는 Rust 컴파일러 에러 해설의 일부예요.
에러 메시지
섹션 제목: “에러 메시지”error[E0658]: use of unstable library feature `iter_intersperse` --> src/main.rs:3:47 |3 | let joined: String = tags.iter().copied().intersperse(", ").collect(); // ❌ nightly 전용 메서드 | ^^^^^^^^^^^ | = note: see issue #79524 <https://github.com/rust-lang/rust/issues/79524> for more informationnote:는 “자세한 내용은 이슈 #79524를 보라”는 뜻이에요.
이 에러를 내는 프로그램은 다음과 같아요.
fn main() { let tags = ["rust", "web", "cli"]; let joined: String = tags.iter().copied().intersperse(", ").collect(); // ❌ nightly 전용 메서드 println!("{}", joined);}무슨 뜻인가요
섹션 제목: “무슨 뜻인가요”^^^^^^^^^^^는 3번째 줄의 intersperse를 가리켜요. 제목 줄은 백틱 안에 기능 이름(feature name) iter_intersperse를 알려 줘요. Rust 팀이 표준 라이브러리의 이 미완성 부분을 부르는 이름이에요. note:는 그 기능을 논의하고 있는 GitHub 이슈로 연결돼요.
즉 rustc는 메서드를 찾았어요. 내가 무슨 뜻으로 썼는지도 정확히 알아요. 다만 컴파일하지 않을 뿐이에요. intersperse가 아직 불안정(unstable)으로 표시돼 있거든요. 완성되기 전에 이름, 인자, 동작이 바뀔 수도 있고, 아예 없어질 수도 있어요.
라이브러리 기능이 아니라 언어 기능일 때는 제목 줄이 다른 모양으로 나오지만, 뜻은 같아요. the `!` type is experimental(! 타입은 실험적이다), `try` expression is experimental(try 표현식은 실험적이다), associated type defaults are unstable(연관 타입 기본값은 불안정하다) 같은 것들이요.
가게 진열대에 “직원 전용, 테스트 중” 스티커가 붙은 신상품이 있는 것과 비슷해요. 볼 수도 있고, 라벨을 읽을 수도 있지만, 아직 계산대에서 팔아 주지 않아요.
Rust가 이렇게 하는 이유
섹션 제목: “Rust가 이렇게 하는 이유”Rust는 굳게 약속해요. 오늘 안정판 Rust에서 컴파일되는 코드는 앞으로 나올 모든 안정판 Rust 1.x에서도 계속 컴파일된다고요. 이 약속을 지키려고, 새 기능은 먼저 nightly 채널에 들어가요. 거기서 사람들이 써 볼 수 있고, 설계도 아직 바뀔 수 있어요. 기능이 완성돼야 비로소 안정판이 되는데, 보통 몇 달에서 몇 년의 테스트를 거쳐요.
안정판 Rust는 불안정한 기능을 아예 컴파일하지 않아요. 그래서 발밑에서 바뀔지도 모르는 것 위에 코드를 쌓을 수가 없어요. 정말 써 보고 싶다면, nightly에서는 #![feature(iter_intersperse)]처럼 이름으로 켤 수 있어요. 안정판에서는 그 줄조차 에러(E0554)예요.
표준 라이브러리 문서는 두 종류를 나란히 보여 줘요. 안정된 항목은 오른쪽에 1.82.0 같은 버전 번호가 있어요. 그 항목이 안정판이 된 Rust 버전이에요. 불안정한 항목에는 “🔬 This is a nightly-only experimental API.”(nightly 전용 실험적 API)라고 적힌 상자가 있어요. 코드를 쓰기 전에 E0658을 알아차리는 가장 빠른 방법이 그 상자예요. Rust의 채널과 rustup이 어떻게 맞물리는지는 Rust 도구와 설치를 참고하세요.
고치는 방법
섹션 제목: “고치는 방법”방법 1: 안정판 대안 쓰기
섹션 제목: “방법 1: 안정판 대안 쓰기”거의 언제나 이 방법을 고르세요. 불안정한 메서드는 대개 안정판 Rust로 이미 할 수 있는 일의 지름길이에요. 문자열을 구분자로 이어 붙이려면, 슬라이스나 Vec의 join이 intersperse(...).collect()가 할 일을 해 줘요.
fn main() { let tags = ["rust", "web", "cli"]; let joined = tags.join(", "); println!("{}", joined);
// 반복자가 만든 문자열: 먼저 Vec으로 모은 다음 join해요. let upper: Vec<String> = tags.iter().map(|t| t.to_uppercase()).collect(); println!("{}", upper.join(" | "));}실행 결과:
rust, web, cliRUST | WEB | CLI반복자 체인 하나로 끝까지 쓰고 싶다면, 인기 있는 itertools 크레이트에 반복자용 안정판 join과 intersperse가 있어요. 문자열과 반복자를 참고하세요.
방법 2: 문서에서 “nightly-only” 표시 확인하기
섹션 제목: “방법 2: 문서에서 “nightly-only” 표시 확인하기”문서, AI 답변, 블로그 글에서 메서드를 복사해 왔을 때 이 방법을 고르세요. 표준 라이브러리 문서에서 그 메서드를 열어 보세요. 🔬 상자가 있다면, 조금 더 찾아서 안정판 방법을 쓰세요. 흔한 예가 .try_collect()예요.
error[E0658]: use of unstable library feature `iterator_try_collect` --> src/main.rs:3:80 |3 | let numbers: Result<Vec<i32>, _> = inputs.iter().map(|s| s.parse::<i32>()).try_collect(); // ❌ nightly 전용 | ^^^^^^^^^^^ | = note: see issue #94047 <https://github.com/rust-lang/rust/issues/94047> for more information문제가 되는 프로그램은 이래요.
fn main() { let inputs = ["3", "14", "x"]; let numbers: Result<Vec<i32>, _> = inputs.iter().map(|s| s.parse::<i32>()).try_collect(); // ❌ nightly 전용 println!("{:?}", numbers);}안정판 Rust는 평범한 collect()로 이미 이걸 해요. 항목이 Result이고 Result<Vec<_>, _>로 모으면, 모든 값이 담긴 Ok나 첫 번째 Err를 얻어요.
use std::num::ParseIntError;
fn parse_all(inputs: &[&str]) -> Result<Vec<i32>, ParseIntError> { inputs.iter().map(|s| s.parse::<i32>()).collect()}
fn main() { println!("{:?}", parse_all(&["3", "14", "15"])); println!("{:?}", parse_all(&["3", "x", "15"]));}실행 결과:
Ok([3, 14, 15])Err(ParseIntError { kind: InvalidDigit })그 밖에 만날 수 있는 불안정한 메서드와 안정판 대안이에요. 반복자의 .array_chunks()(iter_array_chunks)는 슬라이스의 .as_chunks()나 .chunks()로, .map_windows()는 슬라이스의 .windows()로 바꾸세요. Result와 슬라이스를 참고하세요.
방법 3: 최근에 안정화된 기능이라면 Rust 업데이트하기
섹션 제목: “방법 3: 최근에 안정화된 기능이라면 Rust 업데이트하기”문서에 🔬 상자 대신 버전 번호가 있거나, 같은 코드가 친구 컴퓨터나 Playground에서는 컴파일될 때 이 방법을 고르세요. 그렇다면 그 기능은 안정판이 맞아요. 다만 내 컴파일러보다 새로울 뿐이에요. 예를 들어 슬라이스의 as_chunks는 Rust 1.88에서 안정판이 됐어요. 그보다 오래된 Rust에서는 E0658이 나지만, 최신 Rust에서는 그냥 동작해요.
fn main() { let readings = [21, 22, 19, 20, 23]; let (pairs, rest) = readings.as_chunks::<2>(); for [a, b] in pairs { println!("짝: {}, {}", a, b); } println!("남은 값: {:?}", rest);}실행 결과:
짝: 21, 22짝: 19, 20남은 값: [23]버전을 확인하고 업데이트하세요.
rustc --versionrustup update그 뒤에도 rustc --version이 여전히 옛 버전을 보여 준다면, 프로젝트에 rust-toolchain.toml 파일이 있는지 찾아보세요. 그 파일은 프로젝트를 한 Rust 버전에 고정하고, rustup show는 지금 어떤 버전이 활성화돼 있는지 알려 줘요. Rust 도구와 설치를 참고하세요.
방법 4: 정말 원할 때만 #![feature]로 nightly 기능 켜기
섹션 제목: “방법 4: 정말 원할 때만 #![feature]로 nightly 기능 켜기”이 방법은 마지막에, 안정판 대안이 없고 앞으로의 nightly에서 코드가 깨져도 괜찮을 때만 고르세요. 두 가지가 필요해요. 에러에 나온 기능 이름을 쓴 #![feature(...)] 줄을 main.rs(또는 lib.rs) 맨 위에 쓰고, nightly 컴파일러를 써야 해요. 안정판에서는 #![feature] 줄 자체가 거부돼요.
error[E0554]: `#![feature]` may not be used on the stable release channel --> src/main.rs:1:1 |1 | #![feature(iter_intersperse)] // ❌ nightly Rust에서만 허용돼요 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^“안정판 릴리스 채널에서는 #![feature]를 쓸 수 없다”는 뜻이에요. nightly에서만 빌드되는 프로그램은 이래요.
#![feature(iter_intersperse)] // ❌ nightly Rust에서만 허용돼요
fn main() { let tags = ["rust", "web", "cli"]; let joined: String = tags.iter().copied().intersperse(", ").collect(); println!("{}", joined);}안정판 Rust 옆에 nightly를 설치하고, 이 프로젝트나 이 명령에서만 쓰세요.
rustup toolchain install nightlycargo +nightly run여기서는 스스로에게 솔직해지세요. 공부, 테스트, 작은 도구에는 nightly도 괜찮아요. 다른 사람들이 의존하는 라이브러리나, 계속 관리해야 하는 코드라면 안정판에 머무르세요. 여러분이 쓰는 크레이트도 대부분 그렇게 해요.
자주 보게 되는 곳
섹션 제목: “자주 보게 되는 곳”짝의 목록을 원했는데 Vec<i32, i32>라고 쓴 경우. Vec의 두 번째 매개변수는 메모리 할당자(allocator)인데, 이건 불안정해요. 그래서 첫 에러는 allocator_api에 관한 거예요(그 뒤로 에러가 몇 개 더 나와요).
error[E0658]: use of unstable library feature `allocator_api` --> src/main.rs:2:26 |2 | let points: Vec<i32, i32> = vec![]; // ❌ (x, y) 짝의 목록을 원했어요 | -----^^^ | | | help: consider wrapping the inner types in tuple: `(i32, i32)`help는 “안쪽 타입들을 튜플로 감싸 보라: (i32, i32)“라는 뜻이에요.
fn main() { let points: Vec<i32, i32> = vec![]; // ❌ (x, y) 짝의 목록을 원했어요 println!("점 {}개", points.len());}해결: help대로 Vec<(i32, i32)>라고 쓰세요. 벡터와 튜플을 참고하세요. 같은 실수를 Option이나 Result에 하면 E0107이에요.
내 시그니처에 쓴 ! 타입. !는 “절대 일어나지 않음”을 뜻해요. 절대 반환하지 않는 함수의 반환 타입으로는 쓸 수 있지만, 그 밖의 곳에서는 아직 불안정해요.
error[E0658]: the `!` type is experimental --> src/main.rs:1:34 |1 | fn default_port() -> Result<u16, !> { // ❌ 여기서 `!` 타입은 nightly 전용이에요 | ^fn default_port() -> Result<u16, !> { // ❌ 여기서 `!` 타입은 nightly 전용이에요 Ok(8080)}
fn main() { println!("{:?}", default_port());}해결: 안정판의 “이 에러는 일어날 수 없음” 타입인 std::convert::Infallible을 쓰거나, 실패할 일이 없다면 그냥 u16을 반환하세요.
try 블록. try { ... } 블록을 쓰면 함수를 따로 만들지 않고도 ?를 쓸 수 있지만, nightly 전용이에요(`try` expression is experimental). 해결: 그 코드를 Result를 반환하는 작은 함수로 옮기고, 방법 2처럼 거기서 ?를 쓰세요. Result를 참고하세요.
E0658은 아니지만 관련된 경우도 있어요. if let Some(a) = age && a >= 18처럼 2024 에디션용으로 쓴 코드는 옛 에디션에서 let chains are only allowed in Rust 2024 or later(let 체인은 Rust 2024 이후에서만 허용된다)를 내요. 해결: Cargo.toml에 edition = "2024"라고 쓰거나, if 두 개를 중첩하세요.
관련 에러
섹션 제목: “관련 에러”- E0554:
#![feature]may not be used on the stable release channel. 안정판에서 방법 4를 시도하면 이어서 나는 에러예요. - E0599: 메서드를 찾을 수 없어요. 메서드가 아예 없을 때(또는 추가하지 않은 크레이트에 있을 때)는 E0658 대신 이게 나요.
- E0107: 제네릭 인자 개수가 틀렸어요.
Option<i32, i32>같은 경우예요(Vec<i32, i32>경우의 사촌이에요). - E0277: 트레이트 바운드를 만족하지 않아요.
Vec<i32, i32>뒤에 따라 나오는 에러 중 하나예요. - E0463: 크레이트를 찾을 수 없어요.
itertools로 바꾸고Cargo.toml에 추가하는 걸 잊었을 때 나요. - 전체 컴파일러 에러: 에러 페이지 전체 목록이에요.
이해도 점검
섹션 제목: “이해도 점검”이해도 점검
1. 어떤 메서드의 표준 라이브러리 문서에 "This is a nightly-only experimental API"라는 상자가 있어요. 안정판 Rust에서 호출하면 어떻게 될까요?
2. .try_collect()가 E0658을 내요. Result 반복자를 Result<Vec<_>, _>로 바꾸는 보통의 안정판 방법은 무엇일까요?
3. Playground에서는 컴파일되는 코드가, 문서에 1.88.0이라고 적힌 메서드 때문에 내 컴퓨터에서는 E0658을 내요. 먼저 무엇을 해 볼까요?
점수: 0 / 3
더 알아보기
섹션 제목: “더 알아보기”- E0658 — Rust error codes index (영어): 공식 설명이에요. nightly에서
#![feature]줄이 기능을 어떻게 켜는지도 나와요. - 부록 G - 러스트가 만들어지는 과정과 “Nightly 러스트” — The Rust Programming Language 한국어판: stable, beta, nightly, 릴리스 기차, 그리고 불안정한 기능이 어떻게 안정판이 되는지 설명해요.
- Channels — The rustup book (영어): nightly 설치,
cargo +nightly, 프로젝트별 툴체인 설정을 다뤄요. - The Unstable Book (영어): E0658에서 볼 수 있는 모든 불안정한 기능 이름과 각각의 짧은 설명이에요.
slice::join— standard library docs (영어): 문자열을 구분자로 이어 붙이는 안정판 방법으로,intersperse의 대안이에요.