콘텐츠로 이동

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 scope
help: 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에서는 많은 메서드가 타입 자체에 속하지 않아요. 트레이트(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의 바운드가 약속하는 메서드만 호출하게 해 줘요.

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 started
▶ 직접 실행해 보기

b"..."는 바이트 문자열이라 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를 참고하세요.

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 parameter
2 | 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()처럼요.

이해도 점검

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