Ir al contenido

Error E0599 de Rust: no method named X found (método no encontrado)

El error E0599 significa que llamaste a un método que Rust no encuentra en ese tipo. Es muy común, y la causa suele ser una de unas pocas: un trait que no importaste, un Option que no desenvolviste, un Vec que trataste como si fuera un iterador o un simple error al escribir el nombre. La buena noticia es que las líneas help: de rustc muchas veces te dicen la solución exacta. Esta página forma parte de la guía de errores del compilador.

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;
|

Este es el programa que lo produjo:

use std::io;
fn main() {
let mut out = io::stdout();
out.write_all(b"Server started\n").unwrap();
}

Los ^^^^ señalan el nombre del método, write_all, y la primera línea te dice en qué tipo buscó Rust: Stdout. Así que el mensaje se lee como “busqué en Stdout y no encontré ningún método llamado write_all que pueda usar aquí”.

El tipo de esa primera línea es la pista más útil de todo el mensaje. Si dice Option<T>, Result<T, E>, Vec<_> o un parámetro de tipo T cuando esperabas otra cosa, ya sabes cuál de las soluciones de abajo necesitas.

En Rust, muchos métodos no pertenecen al tipo en sí. Vienen de un trait. write_all viene del trait Write, y Stdout lo implementa. Pero los métodos de un trait solo funcionan en un archivo que tenga ese trait en su ámbito (scope), normalmente gracias a una línea use. Eso es lo que significa “items from traits can only be used if the trait is in scope” (los elementos de un trait solo se pueden usar si el trait está en el ámbito).

Esta regla hace que el código sea predecible. Dos crates pueden añadir, cada uno con su propio trait, un método llamado write_all al mismo tipo. Si todos los traits estuvieran siempre activos, no sabrías a cuál se refiere una llamada. Con la regla, solo cuentan los traits que importaste.

Las otras causas vienen de lo estrictos que son los tipos en Rust. Un Option<&str> no es un &str, así que no tiene los métodos de &str. Un T genérico podría ser cualquier tipo, así que Rust solo te deja llamar a los métodos que prometen los bounds (restricciones) de T.

Elige esta cuando la ayuda dice “items from traits can only be used if the trait is in scope”. Añade la línea use que sugiere rustc.

use std::io::{self, Write};
fn main() {
let mut out = io::stdout();
out.write_all(b"Server started\n").unwrap();
}

Salida:

Server started
▶ Pruébalo tú mismo

(El texto se queda en inglés porque b"..." es una cadena de bytes, y en ella solo se permiten caracteres ASCII, sin acentos.)

Lo mismo pasa con el crate rand. Sin la importación, rng.random_range(1..=6) falla, y rustc te dice qué trait tienes que traer:

help: trait `RngExt` which provides `random_range` is implemented but not in scope; perhaps you want to import it
|
1 + use rand::RngExt;

Ojo: en rand 0.10 el trait se llama RngExt. Los tutoriales antiguos dicen use rand::Rng, y en rand 0.10 esa importación te da exactamente este mismo error. Sigue la línea help:, no el tutorial.

Solución 2: Saca primero el valor del Option o del Result

Sección titulada «Solución 2: Saca primero el valor del Option o del Result»

Elige esta cuando el tipo del error es Option<T> o Result<T, E>. El valor que quieres está dentro, y tienes que sacarlo antes de llamar a sus métodos.

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>`

rustc dice que to_uppercase no existe para Option<&&str>: el método es de las cadenas de texto, no del Option que las envuelve. first() devuelve un Option, porque la lista podría estar vacía. rustc sugiere .expect(...), que funciona, pero hace que el programa falle con None. Normalmente es mejor manejar los dos casos:

fn main() {
let guests = vec!["ana", "bo", "chen"];
match guests.first() {
Some(name) => println!("Primer invitado: {}", name.to_uppercase()),
None => println!("Todavía no hay invitados"),
}
let shout = guests.last().map(|name| name.to_uppercase());
println!("Último invitado: {:?}", shout);
}

Salida:

Primer invitado: ANA
Último invitado: Some("CHEN")
▶ Pruébalo tú mismo

.map() ejecuta tu código sobre el valor de dentro y conserva el envoltorio Option. Para un Result (por ejemplo, el de .parse()), usa match, .unwrap_or(...) o ? dentro de una función que devuelva Result. Mira Option y Result.

Elige esta cuando llamas a .map(), .filter() u otro método de iterador directamente sobre un Vec. Aquí el error se ve distinto:

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`

Con algunos métodos, como filter, el mensaje es más amable. rustc dice que el Vec<i32> “is not an iterator” (no es un iterador) y añade help: call `.into_iter()` first. Misma causa, misma solución.

Vec<{integer}>: Iterator no se cumple (“not satisfied”) porque un Vec es una colección, no un iterador. Pídele uno con .iter() (presta los elementos) o .into_iter() (se los lleva):

fn main() {
let scores = vec![70, 85, 92];
let curved: Vec<i32> = scores.iter().map(|s| s + 5).collect();
println!("{:?}", curved);
}

Salida:

[75, 90, 97]
▶ Pruébalo tú mismo

Solución 4: Añade un trait bound al T genérico

Sección titulada «Solución 4: Añade un trait bound al T genérico»

Elige esta cuando el error dice que el método no se encontró “for type parameter T” (para el parámetro de tipo T). Dentro de una función genérica, Rust solo sabe lo que prometen los bounds de T. Un T sin más no promete nada, así que no tiene métodos.

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 {
| ++++++++++

rustc te indica qué trait define to_string y te muestra con ++++ dónde añadirlo. Pon el bound que sugiere. Ahora solo se aceptan tipos que se pueden convertir en cadena de texto:

fn describe<T: ToString>(item: T) -> String {
format!("[{}]", item.to_string())
}
fn main() {
println!("{}", describe(42));
println!("{}", describe("listo"));
}

Salida:

[42]
[listo]
▶ Pruébalo tú mismo
  • Un error de escritura o un método de otro lenguaje. tasks.push_back(...) sobre un Vec da help: you might have meant to use `push`, y tasks.lenght() da help: there is a method `len` with a similar name. Solución: usa el nombre que sugiere rustc.
  • Llamar a un Type::new() que nunca escribiste. Rust no regala constructores: Account::new("Ana", 100) falla con no associated function or constant named `new` found for struct `Account`. Solución: añade impl Account { fn new(owner: &str, balance: i64) -> Self { ... } }, o créalo directamente con Account { owner: ..., balance: ... }. Mira Structs.
  • Llamar a una función asociada con un punto. Si fn new() -> Self no tiene parámetro self, acc.new() falla con “this is an associated function, not a method” (es una función asociada, no un método). Solución: llámala sobre el tipo, Account::new().

Comprueba lo aprendido

1. rustc dice "items from traits can only be used if the trait is in scope". ¿Qué deberías hacer?

2. names.first().to_uppercase() falla con E0599 para Option<&&str>. ¿Por qué?

3. Llamas a scores.filter(...) sobre un Vec<i32> y rustc dice "Vec<i32> is not an iterator". ¿Cuál es la solución?

Puntuación: 0 / 3