Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I disambiguate traits in Rust?

Tags:

rust

I want to use the write_fmt method on two different types of object:

use std::fmt::Write;
use std::io::Write;

fn main() {
    let mut a = String::new();
    let mut b = std::fs::File::create("test").unwrap();

    a.write_fmt(format_args!("hello"));
    b.write_fmt(format_args!("hello"));
}

I get an error when using Write because they are both named the same:

error[E0252]: a trait named `Write` has already been imported in this module
 --> src/main.rs:8:5
  |
7 | use std::fmt::Write;
  |     --------------- previous import of `Write` here
8 | use std::io::Write;
  |     ^^^^^^^^^^^^^^ `Write` already imported
      a.write_fmt(format_args!("hello"));
      b.write_fmt(format_args!("hello"));

Or I get an error saying the trait is not available:

error[E0599]: no method named `write_fmt` found for type `std::fs::File` in the current scope
  --> src/main.rs:76:4
   |
76 |    b.write_fmt(format_args!("hello"));
   |      ^^^^^^^^^
   |
   = help: items from traits can only be used if the trait is in scope; the following trait is implemented but not in scope, perhaps add a `use` for it:
   = help: candidate #1: `use std::io::Write;`
like image 648
ashleysmithgpu Avatar asked Jul 06 '17 15:07

ashleysmithgpu


People also ask

How do you implement traits in Rust?

Implementing a trait in Rust To implement a trait, declare an impl block for the type you want to implement the trait for. The syntax is impl <trait> for <type> . You'll need to implement all the methods that don't have default implementations.

Are Rust traits interfaces?

Rust is not an object oriented language. And traits are not exactly interfaces.

Can traits have fields Rust?

Traits can't have fields. If you want to provide access to a field from a trait, you need to define a method in that trait (like, say, get_blah ).

Does Rust have inheritance?

Inheritance as a Type System and as Code SharingIf a language must have inheritance to be an object-oriented language, then Rust is not. There is no way to define a struct that inherits the parent struct's fields and method implementations.

What is a trait in rust?

A trait tells the Rust compiler about functionality a particular type has and can share with other types. Traits are an abstract definition of shared behavior amongst different types. So, we can say that traits are to Rust what interfaces are to Java or abstract classes are to C++. A trait method is able to access other methods within that trait.

How do I subclass a rust trait?

Rust has a way to specify that a trait is an extension of another trait, giving us something similar to subclassing in other languages. To create a subtrait, indicate that it implements the supertrait in the same way you would with a type:

What is the cornerstone of abstraction in rust?

The cornerstone of abstraction in Rust is traits: Traits are Rust's sole notion of interface. A trait can be implemented by multiple types, and in fact new traits can provide implementations for existing types. On the flip side, when you want to abstract over an unknown type,...

What is the self keyword in rust?

In a trait definition (including the one above), we have access to a special type: Self. Self is a special keyword that is only available within type definitions, trait definitions, and impl blocks (according to the Rust documentation ). In trait definitions, it refers to the implementing type.


2 Answers

You can call the trait method directly:

fn main() {
    let mut a = String::new();
    let mut b = std::fs::File::create("test").unwrap();

    std::fmt::Write::write_fmt(&mut a, format_args!("hello"));
    std::io::Write::write_fmt(&mut b, format_args!("hello"));
}

You can also choose to only import the trait in a smaller scope:

fn main() {
    let mut a = String::new();
    let mut b = std::fs::File::create("test").unwrap();

    {
        use std::fmt::Write;
        a.write_fmt(format_args!("hello"));
    }

    {
        use std::io::Write;
        b.write_fmt(format_args!("hello"));
    }
}

Note that if you choose to use a smaller scope, you can also use the write! macro directly:

fn main() {
    let mut a = String::new();
    let mut b = std::fs::File::create("test").unwrap();

    {
        use std::fmt::Write;
        write!(a, "hello");
    }

    {
        use std::io::Write;
        write!(b, "hello");
    }
}

In either case, you should handle the Result return value.

See also:

  • How to call a method when a trait and struct use the same name?
like image 141
Shepmaster Avatar answered Sep 28 '22 03:09

Shepmaster


You can specify an alias for use:

use std::fmt::Write as FmtWrite;
use std::io::Write;

fn main() {
    let mut a = String::new();
    let mut b = std::fs::File::create("test").unwrap();

    a.write_fmt(format_args!("hello"));
    b.write_fmt(format_args!("hello"));
}

If you just want to call the traits method, you can even just bring them in scope:

use std::fmt::Write as _;
use std::io::Write as _;

fn main() {
    let mut a = String::new();
    let mut b = std::fs::File::create("test").unwrap();

    a.write_fmt(format_args!("hello"));
    b.write_fmt(format_args!("hello"));
}

Be careful, this solution works when different types implement different traits with the same name. If the same type implements different traits with the same name, you must use Shepmaster's answer:

mod foo {
    pub trait Trait {
        fn do_something(&self) {}
    }
}

mod bar {
    pub trait Trait {
        fn do_something(&self) {}
    }
}

pub struct Concrete {}
impl foo::Trait for Concrete {}
impl bar::Trait for Concrete {}

fn main() {
    let x = Concrete {};

    {
        use foo::Trait; // use limited to scope

        x.do_something(); // call foo::Trait::do_something
    }
    {    
        foo::Trait::do_something(&x); // complete path to disambiguate
        bar::Trait::do_something(&x); // complete path to disambiguate
    }
    {
        use foo::Trait as FooTrait;
        use bar::Trait;

        x.do_something(&x); // ERROR: multiple applicable items in scope
    }
}
like image 43
Boiethios Avatar answered Sep 28 '22 04:09

Boiethios