Rust 에러 E0599: no method named X found (메서드를 찾을 수 없음)
E0599는 Rust가 그 타입에서 찾을 수 없는 메서드를 호출했다는 뜻이에요. 아주 흔한 에러이고, 원인도 대개 몇 가지 중 하나예요. 가져오지(import) 않은 트레이트, 꺼내지 않은 Option, 반복자처럼 다룬 Vec, 아니면 단순한 오타예요. 다행히 rustc의 help: 줄이 정확한 해결책을 알려 줄 때가 많아요. 이 페이지는 Rust 컴파일러 에러 해설의 일부예요.
에러 메시지
섹션 제목: “에러 메시지”error[E0599]: no method named `write_all` found for struct `Stdout` in the current scope --> src/main.rs:5:9 |5 | out.write_all(b"Server started\n").unwrap(); | ^^^^^^^^^ | = note: the method is available for `Stdout` here | = help: items from traits can only be used if the trait is in scopehelp: trait `Write` which provides `write_all` is implemented but not in scope; perhaps you want to import it |1 + use std::io::Write; |첫 줄은 “현재 스코프에서 Stdout 구조체에 write_all이라는 메서드가 없다”는 뜻이에요. help는 “트레이트의 항목은 그 트레이트가 스코프 안에 있을 때만 쓸 수 있다”, “write_all을 제공하는 Write 트레이트가 구현되어 있지만 스코프에 없으니 가져와 보라”고 알려 줘요.
이 에러를 내는 프로그램은 다음과 같아요.
use std::io;
fn main() { let mut out = io::stdout(); out.write_all(b"Server started\n").unwrap();}무슨 뜻인가요
섹션 제목: “무슨 뜻인가요”^^^^ 표시는 메서드 이름 write_all을 가리키고, 첫 줄은 Rust가 어떤 타입에서 메서드를 찾았는지 알려 줘요. 바로 Stdout이에요. 그러니까 이 메시지는 “Stdout을 살펴봤는데, 여기서 쓸 수 있는 write_all이라는 메서드가 없다”는 말이에요.
첫 줄에 나오는 타입이 이 에러에서 가장 쓸모 있는 단서예요. 예상과 달리 Option<T>, Result<T, E>, Vec<_>, 또는 타입 매개변수 T라고 나와 있다면, 아래의 어떤 방법이 필요한지 벌써 알 수 있어요.
Rust가 이렇게 하는 이유
섹션 제목: “Rust가 이렇게 하는 이유”Rust에서는 많은 메서드가 타입 자체에 속하지 않아요. 트레이트(trait)에서 와요. write_all은 Write 트레이트에서 오고, Stdout은 그 트레이트를 구현해요. 하지만 트레이트의 메서드는 그 트레이트가 스코프 안에 있는 파일에서만 쓸 수 있어요. 보통 use 줄로 가져오죠. “items from traits can only be used if the trait is in scope”가 바로 이 뜻이에요.
이 규칙 덕분에 코드가 예측 가능해져요. 두 크레이트가 서로 다른 트레이트로 같은 타입에 write_all이라는 메서드를 각각 추가할 수도 있어요. 모든 트레이트가 늘 켜져 있다면, 호출이 어느 쪽을 뜻하는지 알 수 없겠죠. 이 규칙이 있으면 내가 가져온 트레이트만 쳐요.
다른 원인들은 Rust의 엄격한 타입에서 와요. Option<&str>은 &str이 아니어서 &str의 메서드가 없어요. 제네릭 T는 어떤 타입이든 될 수 있으니, Rust는 T의 바운드가 약속하는 메서드만 호출하게 해 줘요.
고치는 방법
섹션 제목: “고치는 방법”방법 1: 트레이트 가져오기
섹션 제목: “방법 1: 트레이트 가져오기”help가 “items from traits can only be used if the trait is in scope”라고 말할 때 이 방법을 고르세요. rustc가 제안하는 use 줄을 추가하면 돼요.
use std::io::{self, Write};
fn main() { let mut out = io::stdout(); out.write_all(b"Server started\n").unwrap();}실행 결과:
Server startedb"..."는 바이트 문자열이라 ASCII 글자만 쓸 수 있어서, 이 메시지는 영어로 두었어요.
rand 크레이트에서도 같은 일이 생겨요. 가져오지 않으면 rng.random_range(1..=6)이 실패하고, rustc가 어떤 트레이트를 가져와야 하는지 알려 줘요.
help: trait `RngExt` which provides `random_range` is implemented but not in scope; perhaps you want to import it |1 + use rand::RngExt;주의하세요. rand 0.10에서는 트레이트 이름이 RngExt예요. 예전 튜토리얼에는 use rand::Rng라고 나와 있는데, rand 0.10에서 그렇게 가져오면 바로 이 에러가 똑같이 나요. 튜토리얼이 아니라 help: 줄을 따르세요.
방법 2: Option이나 Result에서 먼저 값 꺼내기
섹션 제목: “방법 2: Option이나 Result에서 먼저 값 꺼내기”에러에 나온 타입이 Option<T>나 Result<T, E>일 때 이 방법을 고르세요. 원하는 값은 그 안에 들어 있어서, 메서드를 부르기 전에 꺼내야 해요.
error[E0599]: no method named `to_uppercase` found for enum `Option<T>` in the current scope --> src/main.rs:4:39 |4 | println!("First guest: {}", first.to_uppercase()); | ^^^^^^^^^^^^ method not found in `Option<&&str>`“Option<&&str>에서 메서드를 찾을 수 없다”는 뜻이에요. first()는 목록이 비어 있을 수 있으니 Option을 반환해요. rustc는 .expect(...)를 제안하는데, 동작은 하지만 None이면 프로그램이 멈춰요. 보통은 두 경우를 모두 처리하는 게 더 좋아요.
fn main() { let guests = vec!["ana", "bo", "chen"];
match guests.first() { Some(name) => println!("첫 번째 손님: {}", name.to_uppercase()), None => println!("아직 손님이 없어요"), }
let shout = guests.last().map(|name| name.to_uppercase()); println!("마지막 손님: {:?}", shout);}실행 결과:
첫 번째 손님: ANA마지막 손님: Some("CHEN").map()은 안쪽 값에 코드를 실행하고 Option 포장은 그대로 둬요. Result라면(예를 들어 .parse()의 결과) match나 .unwrap_or(...)를 쓰거나, Result를 반환하는 함수 안에서 ?를 쓰세요. Option과 Result를 참고하세요.
방법 3: Vec에 .iter() 호출하기
섹션 제목: “방법 3: Vec에 .iter() 호출하기”Vec에 바로 .map(), .filter() 같은 반복자 메서드를 호출했을 때 이 방법을 고르세요. 이때는 에러 모양이 조금 달라요.
error[E0599]: the method `map` exists for struct `Vec<{integer}>`, but its trait bounds were not satisfied --> src/main.rs:3:35 |3 | let curved: Vec<i32> = scores.map(|s| s + 5).collect(); | ^^^ | = note: the following trait bounds were not satisfied: `Vec<{integer}>: Iterator`“Vec<{integer}>에 map 메서드는 있지만, 트레이트 바운드를 만족하지 않는다”는 뜻이에요. filter 같은 메서드에서는 메시지가 더 친절해요. rustc가 Vec<i32>는 “is not an iterator”(반복자가 아님)라고 말하고 help: call `.into_iter()` first(먼저 .into_iter()를 호출하라)를 덧붙여요. 원인도 해결책도 같아요.
Vec<{integer}>: Iterator가 “not satisfied”(만족되지 않음)인 이유는 Vec이 컬렉션이지 반복자가 아니기 때문이에요. .iter()(항목을 빌려요)나 .into_iter()(항목을 가져가요)로 반복자를 달라고 하세요.
fn main() { let scores = vec![70, 85, 92]; let curved: Vec<i32> = scores.iter().map(|s| s + 5).collect(); println!("{:?}", curved);}실행 결과:
[75, 90, 97]방법 4: 제네릭 T에 트레이트 바운드 추가하기
섹션 제목: “방법 4: 제네릭 T에 트레이트 바운드 추가하기”에러가 “for type parameter T”(타입 매개변수 T에서) 메서드를 찾지 못했다고 말할 때 이 방법을 고르세요. 제네릭 함수 안에서 Rust는 T의 바운드가 약속하는 것만 알아요. 아무것도 붙지 않은 T는 아무것도 약속하지 않으니, 메서드도 없어요.
error[E0599]: no method named `to_string` found for type parameter `T` in the current scope --> src/main.rs:2:26 |1 | fn describe<T>(item: T) -> String { | - method `to_string` not found for this type parameter2 | format!("[{}]", item.to_string()) | ^^^^^^^^^ method cannot be called on `T` due to unsatisfied trait bounds |help: the following trait defines an item `to_string`, perhaps you need to restrict type parameter `T` with it: |1 | fn describe<T: ToString>(item: T) -> String { | ++++++++++help는 “to_string을 정의하는 트레이트가 있으니, 그 트레이트로 T를 제한해 보라”고 제안해요. rustc가 제안하는 바운드를 추가하세요. 이제 문자열로 바꿀 수 있는 타입만 받아요.
fn describe<T: ToString>(item: T) -> String { format!("[{}]", item.to_string())}
fn main() { println!("{}", describe(42)); println!("{}", describe("준비 완료"));}실행 결과:
[42][준비 완료]자주 보게 되는 곳
섹션 제목: “자주 보게 되는 곳”- 오타나 다른 언어의 메서드 이름.
Vec에tasks.push_back(...)을 쓰면help: you might have meant to use `push`(push를 쓰려던 것 같다)가 나오고,tasks.lenght()를 쓰면help: there is a method `len` with a similar name(비슷한 이름의len메서드가 있다)이 나와요. 해결: rustc가 제안하는 이름을 쓰세요. - 직접 만든 적 없는
Type::new()호출. Rust에는 공짜 생성자가 없어요.Account::new("Ana", 100)은no associated function or constant named `new` found for struct `Account`(구조체Account에new라는 연관 함수나 상수가 없음)로 실패해요. 해결:impl Account { fn new(owner: &str, balance: i64) -> Self { ... } }를 추가하거나,Account { owner: ..., balance: ... }로 바로 만드세요. 구조체를 참고하세요. - 연관 함수를 점으로 호출할 때.
fn new() -> Self에self매개변수가 없는데acc.new()라고 쓰면 “this is an associated function, not a method”(이건 메서드가 아니라 연관 함수예요)로 실패해요. 해결: 타입에서 호출하세요.Account::new()처럼요.
관련 에러
섹션 제목: “관련 에러”- E0425: cannot find value in this scope: 타입의 메서드가 아니라, 이름 자체가 보이지 않아요.
- E0277: trait bound not satisfied: 함수나 연산자가 필요로 하는 트레이트를 타입이 구현하지 않았어요. 제네릭 코드에서 E0599와 함께 나올 때가 많아요.
- E0308: mismatched types:
T가 필요한 곳에Option<T>가 있거나, 그 반대예요. - E0382: use of moved value:
.iter()를.into_iter()로 바꾼 뒤에 자주 따라오는 에러예요. - 전체 컴파일러 에러: 각 에러의 짧은 요약이 있는 전체 목록이에요.
이해도 점검
섹션 제목: “이해도 점검”이해도 점검
1. rustc가 "items from traits can only be used if the trait is in scope"라고 말해요. 어떻게 해야 할까요?
2. names.first().to_uppercase()가 Option<&&str>에 대한 E0599로 실패해요. 왜일까요?
3. Vec<i32>에 scores.filter(...)를 호출했더니 rustc가 "Vec<i32> is not an iterator"라고 말해요. 어떻게 고칠까요?
점수: 0 / 3
더 알아보기
섹션 제목: “더 알아보기”- E0599 — Rust error codes index (영어): 이 에러의 공식 설명이에요.
- 트레이트로 공통된 동작을 정의하기 — The Rust Programming Language 한국어판: 트레이트가 타입에 메서드를 더하는 방법과 트레이트 바운드가 동작하는 방식을 설명해요.
- 반복자로 일련의 아이템들 처리하기 — The Rust Programming Language 한국어판:
iter(),into_iter(), 그리고map같은 반복자 메서드를 다뤄요. Option— 표준 라이브러리 문서 (영어):Option에서 값을 꺼내는 모든 메서드가 있어요.- The Rust prelude — 표준 라이브러리 문서 (영어): 항상 스코프 안에 있는 트레이트 목록이에요.
Write가 왜 거기 없는지도 알 수 있어요.