Rust Error E0790: Cannot Call Associated Function on Trait
E0790 means you asked a trait for something that only a type can give you. Default::default() on its own is like saying “give me the default” without saying the default what. It’s a common error, and the fix is usually to put the type’s name in front: Settings::default() instead of Default::default(). This page shows the fixes first, then explains the difference between a trait and a type, so this error stops surprising you. It’s part of the compiler errors guide.
The error message
Section titled “The error message”error[E0790]: cannot call associated function on trait without specifying the corresponding `impl` type --> src/main.rs:8:20 |8 | let settings = Default::default(); // ❌ the default of which type? | ^^^^^^^^^^^^^^^^^^ cannot call associated function of trait |help: use a fully-qualified path to a specific available implementation |8 | let settings = </* self type */ as Default>::default(); // ❌ the default of which type? | +++++++++++++++++++ +This is the program that produces it:
#[derive(Debug, Default)]struct Settings { volume: u8, dark_mode: bool,}
fn main() { let settings = Default::default(); // ❌ the default of which type? println!("{:?}", settings);}You get the same error when you call your own trait’s function on the trait name, like Shape::new(). Here rustc can see two types that implement Shape, so it lists both as options:
error[E0790]: cannot call associated function on trait without specifying the corresponding `impl` type --> src/main.rs:33:17 | 2 | fn new() -> Self; | ----------------- `Shape::new` defined here...33 | let shape = Shape::new(); | ^^^^^^^^^^^^ cannot call associated function of trait |help: use a fully-qualified path to one of the available implementations |33 | let shape = <Circle as Shape>::new(); | ++++++++++ +33 | let shape = <Square as Shape>::new(); | ++++++++++ +For a trait constant like Plugin::ID, the headline changes slightly: cannot refer to the associated constant on trait without specifying the corresponding `impl` type. Same problem, same fixes.
What it means
Section titled “What it means”Look at what rustc marks:
^^^^underDefault::default(): “cannot call associated function of trait”.defaultis a function that belongs to theDefaulttrait, and you called it through the trait’s name.- The help suggests
</* self type */ as Default>::default(). The/* self type */part is a blank for you to fill in. rustc is asking: “which type’sdefaultdo you mean?” - In the
Shapeexample, rustc fills the blank for you with each type it found (Circle,Square). If only one type implements the trait, it suggests just that one.
Here is the key idea. A trait is a promise: “any type that implements Default can make a starting value of itself”. A type is the thing that keeps the promise: Settings, String, u32 and Vec<T> each keep it in their own way. Default::default() asks the promise itself for a value, but a promise can’t make anything. Only a type can.
Think of a “takeaway available” sign. Many restaurants put it in their window. But you can’t order dinner from the sign; you have to pick a restaurant. Settings::default() is picking the restaurant.
Why Rust does this
Section titled “Why Rust does this”Most trait methods take self, like circle.area(). Those never cause E0790, because the value tells Rust the type: circle is a Circle, so it calls Circle’s area. You can read more about this in Traits.
Some trait functions have no self: constructors like new() and default(), conversions like From::from, and trait constants like ID. With no value to look at, Rust has only two places to learn the type: the name you write in front (Settings::), or the type the result must have (let s: Settings = ...). If neither is there, Rust can’t guess. Many types implement Default, and picking one at random would quietly change what your program does.
This is the same as an interface in Java or C#. You can’t call new on an interface; you need a class that implements it. Rust just tells you about it at compile time, with the exact place to fix.
How to fix it
Section titled “How to fix it”Fix 1: Call it on the type
Section titled “Fix 1: Call it on the type”Choose this almost always. Replace the trait name with the type name. It’s the shortest fix, and it reads well: “the default Settings”, “a new Circle”:
#[derive(Debug, Default)]struct Settings { volume: u8, dark_mode: bool,}
trait Shape { fn new() -> Self; fn name() -> String;}
struct Circle { radius: f64,}
impl Shape for Circle { fn new() -> Self { Circle { radius: 1.0 } } fn name() -> String { String::from("circle") }}
fn main() { let settings = Settings::default(); // instead of Default::default() let shape = Circle::new(); // instead of Shape::new()
println!("{:?}", settings); println!("A {} with radius {}", Circle::name(), shape.radius);}Output:
Settings { volume: 0, dark_mode: false }A circle with radius 1Circle::new() works even though new is defined in the trait, not in an impl Circle block. Rust looks for new on Circle, finds it through impl Shape for Circle, and calls it. The trait must be in scope (defined in the same file, or brought in with use).
Fix 2: Annotate the variable
Section titled “Fix 2: Annotate the variable”Choose this when you like the Default::default() style, or the type name is long. Write the type on the variable, and Rust works out which default to call from that:
#[derive(Debug, Default)]struct Settings { volume: u8, dark_mode: bool,}
fn main() { let settings: Settings = Default::default(); let small: u8 = 42; let big: u32 = From::from(small);
println!("{:?}", settings); println!("{}", big);}Output:
Settings { volume: 0, dark_mode: false }42This only works when the function returns the type itself (Self), as default(), new() and from() do. It does not work for fn name() -> String: knowing the answer is a String tells Rust nothing about which shape you mean. For those, use Fix 1 or Fix 3. More on annotations in Data types.
Fix 3: Fully qualified syntax <Type as Trait>::function()
Section titled “Fix 3: Fully qualified syntax <Type as Trait>::function()”This is the “say everything” form that rustc suggests. Read <Circle as Shape>::new() as “the new that Circle has because it implements Shape”. It always works, but Circle::new() is easier to read, so you only need it when the short form is ambiguous:
- the type implements two traits with a function of the same name, or
- the type has its own function with that name, and you want the trait’s version.
Here a Sale can be written as a CSV row or as a printed report, and both traits have a header(). Writing Sale::header() gives E0034 “multiple applicable items in scope”, so you say which one:
trait Csv { fn header() -> String;}
trait Report { fn header() -> String;}
struct Sale;
impl Csv for Sale { fn header() -> String { String::from("date,amount") }}
impl Report for Sale { fn header() -> String { String::from("Monthly sales") }}
fn main() { println!("{}", <Sale as Csv>::header()); println!("{}", <Sale as Report>::header());}Output:
date,amountMonthly salesThe Advanced traits lesson has another example, with methods that take &self too.
Fix 4: In generic code, use T:: and the turbofish
Section titled “Fix 4: In generic code, use T:: and the turbofish”Choose this when you’re writing a generic function. Inside fn register<T: Plugin>(), the type is T, so call T::name() and T::ID, not Plugin::name(). When you call the function, pass the type with the turbofish ::<Type>, because there’s no argument for Rust to learn it from:
trait Plugin { const ID: u32; fn name() -> String;}
struct Logger;struct Backup;
impl Plugin for Logger { const ID: u32 = 7; fn name() -> String { String::from("logger") }}
impl Plugin for Backup { const ID: u32 = 12; fn name() -> String { String::from("backup") }}
fn register<T: Plugin>() -> String { format!("Plugin #{}: {}", T::ID, T::name())}
fn main() { println!("{}", register::<Logger>()); println!("{}", register::<Backup>());}Output:
Plugin #7: loggerPlugin #12: backupIf you leave out the turbofish and write register(), you get E0283: “cannot infer type of the type parameter T”. T is also the type here, so T:: works the same way as Circle:: in Fix 1. See Generics for more on type parameters.
Where you’ll usually see it
Section titled “Where you’ll usually see it”Default::default() with nothing to go on. let config = Default::default(); fails, but the same call works wherever the type is already known: in a struct field, a function argument, or the “fill in the rest” syntax:
let settings = Settings { volume: 8, ..Default::default() }; // OK: Rust knows it's SettingsFix the failing line with Settings::default() or let config: Settings = Default::default();. See Common traits.
Inside a generic function. Writing the trait name instead of T:
error[E0790]: cannot call associated function on trait without specifying the corresponding `impl` type --> src/main.rs:9:29 |2 | fn name() -> String; | -------------------- `Shape::name` defined here...9 | format!("This is a {}", Shape::name()) | ^^^^^^^^^^^^^ cannot call associated function of trait |help: use the fully-qualified path to the only available implementation |9 | format!("This is a {}", <Circle as Shape>::name()) | ++++++++++ +Careful: rustc suggests <Circle as Shape> because Circle is the only shape so far. That compiles, but the function would then always say “circle”, whatever T is. The right fix is T::name(), as in Fix 4.
Trait constants. println!("{}", Plugin::ID); asks the promise for a number, and only each plugin has one. Fix: Logger::ID, or T::ID in generic code.
From::from(x) with no target. let total = From::from(42u8); gives E0790, because many types can be made from a u8. Fix: u32::from(42u8), or let total: u32 = 42u8.into();. See Conversions.
Related errors
Section titled “Related errors”- E0282: type annotations needed. If you use the value later, like
let c = Shape::new();followed byc.area(), rustc reports E0282 instead. The same fixes work. - E0283: type annotations needed when many types fit, for example
Into::into(n)with no target, or a generic function called without the turbofish. - E0599: no function found.
Settings::default()gives this ifSettingsdoesn’t implementDefault; add#[derive(Default)]. Withlet s: Settings = Default::default();the same mistake shows up as E0277. - E0424:
selfused in a function without aselfparameter. Also about functions that belong to a type rather than to one value. - All compiler errors: the full list of error pages.
Quick check
Section titled “Quick check”Quick check
1. let opts = Default::default(); gives E0790. Options derives Default. Which line fixes it?
2. Why does let s: Settings = Default::default(); compile, but let n: String = Shape::name(); still gives E0790?
3. Inside fn show<T: Shape>(), how should you call the trait function name()?
Score: 0 / 3
Read more
Section titled “Read more”- E0790 — Rust error codes index: the official explanation of this error, with a short example and its fix.
- Traits — The Rust Book: what a trait is, how to implement one, and default implementations.
- Advanced Traits — The Rust Book: includes the section on fully qualified syntax, with the classic
<Dog as Animal>::baby_name()example. - Disambiguating overlapping traits — Rust by Example: a short, runnable example of choosing between two traits that both have a method with the same name.
Default— standard library docs: derivingDefault, implementing it by hand, and the..Default::default()pattern.