如何在 Rust 中定义一个符合 trait 的变量?

How to define a variable that conforms to a trait in Rust?

我想实例化一个变量,我将把它传递给一个接受 T: Write 的函数。它将定义如下:

let outputFile = match matches.opt_str("o") {
    Some(fileName) => File::create(fileName).expect("could not open output file"),
    None => std::io::stdout()
};

目前,编译器会抱怨 arms 中的类型不匹配(File vs. Stdout)。我想要的只是将 outputFile 声明为我可以从 Write 特性调用任何方法的东西,没有别的。

Rust 允许我这样做还是我必须将整个 match 表达式作为参数传递给该函数?

如果你想return实现特征的两个(或更多)独立类型之一,那么你需要return一个trait object

在这种情况下,您需要 return 值来拥有该对象(否则 File 将在 match 结束之前被销毁),所以这是有道理的使用 Box<dyn Write>&WriteBox<dyn Write> 等特征对象是“胖”指针,其中包括指向结构的指针(在本例中为 FileStdout)以及指针到描述如何实现 Write 的 vtable。重要的是,Box<dyn Write>&Write 自动实现 Write.

这是一个工作版本 (playground):

fn get_writer(f: Option<&str>) -> Box<dyn Write> {
    match f {
        Some(file_name) => Box::new(File::create(file_name).expect("could not open output file")),
        None => Box::new(std::io::stdout()),
    }
}

我对你的代码做了一些修改:

  • 添加了 Box<dyn Write> return 值(如果没有函数,您可能需要 let outputFile: Box<dyn Write> = ...;如果没有在某处定义类型,编译器将不会能够推断它需要将这两种类型强制转换为共同的 Box<dyn Write>。一旦编译器知道它需要 Box<dyn Write>,它就可以 强制转换 a Box<File>Box<dyn Write>.

  • 将两个结果装箱。

  • fileName 重命名为 file_name 以匹配 Rust 约定(并消除警告)。