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

5

我想要实例化一个变量,然后将其传递给一个需要 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 trait方法的对象,仅此而已。

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

1个回答

9

如果你想返回实现了一个trait的两种(或多种)不同类型中的一种,那么你需要返回一个trait对象

在这种情况下,你需要返回值拥有对象(否则File将在match结束之前被销毁),因此使用Box<dyn Write>是有意义的。像&WriteBox<dyn Write>这样的trait对象是“fat”指针,它们包括指向结构体(在这种情况下为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>返回值(如果没有函数,您可能需要有let outputFile: Box<dyn Write> = ...;没有定义类型的地方,编译器将无法推断它需要强制转换两种类型为通用的Box<dyn Write>。一旦编译器知道它需要Box<dyn Write>,它就可以将Box<File>强制转换为Box<dyn Write>

  • 对两个结果进行了封装。

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


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