如何在Rust中消除特质歧义?

12

我想在两种不同类型的对象上使用write_fmt方法:

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"));
}

当我使用Write时,由于它们都被命名为相同的名称,因此会出现错误:

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

否则我会收到一个错误,指出该特性不可用:

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;`
2个回答

17
你可以直接调用特征方法:
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"));
}

你也可以选择在更小的作用域中仅导入特征:

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"));
    }
}
请注意,如果您选择使用较小的作用域,也可以直接使用write!宏:
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");
    }
}

无论哪种情况,您都应该处理Result返回值。

另请参见:


10

您可以为 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"));
}

如果你只想调用traits方法,你甚至可以将它们直接引入作用域:

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"));
}

注意,此解决方案仅适用于不同类型实现相同名称的不同特征。如果同一类型实现了具有相同名称的不同特征,则必须使用Shepmaster的答案

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接