如何将 BufWriter<File> 或 BufWriter<StdoutLock> 分配给同一个变量?

How do I assign either BufWriter<File> or BufWriter<StdoutLock> to the same variable?

我正在尝试从标准输出或新创建的文件(如果提供了路径)创建一个 Writer 实例,然后使用该实例写入它。

问题是我无法使用 match 表达式分配它:

let file;
let stdout = stdout();

// argpath, when not None, contains some path to a file to create 
let mut writer = match argpath {
    Some(path) => {
        file = File::create(path)?;
        BufWriter::new(file)
    },
    None => {
        BufWriter::new(stdout.lock())
    }
};

writeln!(writer, "Blah");

编译器明显报错,因为匹配的两臂不return同一个对象,BufWriter<File>BufWriter<StdoutLock>:

error[E0308]: `match` arms have incompatible types
   --> src/main.rs:115:13
    |
109 |       let mut writer = match argpath {
    |  ______________________-
110 | |         Some(path) => {
111 | |             file = File::create(path)?;
112 | |             BufWriter::new(file)
    | |             -------------------- this is found to be of type `std::io::BufWriter<File>`
...   |
115 | |             BufWriter::new(stdout.lock())
    | |             ^^^^^^^^^^^^^^^^^^^^^^ expected struct `File`, found struct `StdoutLock`
116 | |         }
117 | |     };
    | |_____- `match` arms have incompatible types
    |
    = note: expected type `std::io::BufWriter<File>`
             found struct `std::io::BufWriter<StdoutLock<'_>>`
note: return type inferred to be `std::io::BufWriter<File>` here

一般来说,在 Rust 中是否存在现有的编程模式,允许将 BufWriter<> 分配给变量,而不管内部类型如何,因此以下代码可以将其作为常规对象使用实现Write 特征?

您需要动态调度它。为此,通常将它们包装在 Box<dyn Trait>:

let mut writer: BufWriter<Box<dyn Write>> = match argpath {
    Some(path) => {
        file = File::create(path)?;
        BufWriter::new(Box::new(file))
    },
    None => {
        BufWriter::new(Box::new(stdout.lock())
    }
};

Playground