使用字段的通用特征创建结构。预期的struct <trait> found struct <type that“”“implements =”“said =”“trait =”“>

时间:2015-11-19 19:27:25

标签: rust

我试图创建一个具有BufWriter的结构,该结构使用Write特征,这样该结构可以有一个缓冲的编写器,可以是实现该特征的任何东西:{ {1}},File等等。但我在我的函数中遇到了一个问题,即创建结构,说我有Stream。以下是具有相同问题的示例代码。

mismatched types

Playground

错误

use std::fs::File;
use std::io::{BufWriter, Write};

pub struct BufWriterStruct<W: Write> {
    pub writer: Option<BufWriter<W>>,
}

impl <W: Write>BufWriterStruct<W> {
    pub fn new(filename: &str) -> BufWriterStruct<W> {
        BufWriterStruct {
            writer: Some(BufWriter::new(File::create(filename).unwrap())),
        }
    }
}

fn main() {
    let tmp = BufWriterStruct::new("tmp.txt");
}

如果我将error: mismatched types: expected `BufWriterStruct<W>`, found `BufWriterStruct<std::fs::File>` 函数更改为改为使用实现new特征的参数,并在创建Write时使用该参数,则可以正常工作。

我觉得前者应该可以做某种方式。

2 个答案:

答案 0 :(得分:1)

impl <W: Write>BufWriterStruct<W> {
    pub fn new(filename: &str) -> BufWriterStruct<W>

此签名表示以下代码有效:

let tmp : BufWriterStruct<Stdout> = BufWriterStruct::new("tmp.txt");

但是,这显然不适用于new的实施,因为它会生成BufWriterStruct<File>,而不是<StdOut>。如果您想返回BufWriterStruct<File>,则应相应声明new函数:

pub fn new(filename: &str) -> BufWriterStruct<File>

但是,仅此更改将使W块上的impl参数不受约束,编译器将无法为其推断类型。对此最好的解决方案是将new方法放在非通用impl上:

impl BufWriterStruct<File> {
    pub fn new(filename: &str) -> BufWriterStruct<File> {
        // ...
    }
}

请注意,Rust不支持重载(具有相同名称但不同参数列表的方法),因此如果您在同一类型上有两个impl块(忽略通用参数),每个块都有一个名为new,当您尝试调用其中一个时,您会收到错误(从Rust 1.4.0开始,仅在单独的impl块中定义具有相同名称的方法不是编译时错误)。因此,您可能希望使用比new更明确的名称。

答案 1 :(得分:1)

您的错误在于混合通用和特定:

impl <W: Write>BufWriterStruct<W> {
    pub fn new(filename: &str) -> BufWriterStruct<W> {
        BufWriterStruct {
            writer: Some(BufWriter::new(File::create(filename).unwrap())),
        }
    }
}

此处,BufWriter的实例应接受W: Write,由调用者决定,但该函数实际上会创建File

让来电者决定:

impl <W: Write> BufWriterStruct<W> {
    pub fn new(writer: W) -> BufWriterStruct<W> {
        BufWriterStruct {
            writer: Some(BufWriter::new(writer)),
        }
    }
}

当然,这会稍微改变一下调用:

fn main() {
    let tmp = BufWriterStruct::new(File::create("tmp.txt").unwrap());
}

然后it'll work