微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

具有特征字段的结构,但可选

如何解决具有特征字段的结构,但可选

假设我有一个结构体,它的实现写入了 somewhere,即实现了 std::io::Write 特性的东西。但是,我不希望结构拥有它。以下代码有效:

fn main() {
    let mut out = std::io::stdout();
    let mut foo = Foo::new(&mut out);
    foo.print_number(2);
}

struct Foo<'a> {
    out: &'a mut dyn std::io::Write
}

impl<'a> Foo<'a> {
    pub fn new(out: &'a mut dyn std::io::Write) -> Self {
        Self {
            out
        }
    }
    
    pub fn print_number(&mut self,i: isize) {
        writeln!(self.out,"The number is {}",i).unwrap()
    }
}

但是,现在这个写入功能应该是可选的。我认为这听起来很简单,但现在无法编译:

fn main() {
    let mut out = std::io::stdout();
    let mut foo = Foo::new(Some(&mut out));
    foo.print_number(2);
}

struct Foo<'a> {
    out: Option<&'a mut dyn std::io::Write>
}

impl<'a> Foo<'a> {
    pub fn new(out: Option<&'a mut dyn std::io::Write>) -> Self {
        Self {
            out
        }
    }
    
    pub fn print_number(&mut self,i: isize) {
        if self.out.is_some() {
            writeln!(self.out.unwrap(),i).unwrap()
        }
    }
}

因为:

error[E0507]: cannot move out of `self.out` which is behind a mutable reference
        --> src/main.rs:20:26
        |
        20 |                 writeln!(self.out.unwrap(),i).unwrap()
        |                          ^^^^^^^^
        |                          |
        |                          move occurs because `self.out` has type `Option<&mut dyn std::io::Write>`,which does not implement the `copy` trait
        |                          help: consider borrowing the `Option`'s content: `self.out.as_ref()`

我不知道如何解释。

我尝试按照建议将有问题的行更改为:

writeln!(self.out.as_ref().unwrap(),i).unwrap()

但后来我明白了

error[E0596]: cannot borrow data in a `&` reference as mutable
--> src/main.rs:20:26
|
20 |                 writeln!(self.out.as_ref().unwrap(),i).unwrap()
|                          ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable

我真的不知道如何解释这些错误消息,令人惊讶的是,我只是在没有真正理解的情况下将 &mut 散布在随机位置并没有真正获得任何结果!

(顺便说一句,我不确定这是否是解决此问题的“好”方法?我对解决此问题的完全不同的方法持开放态度,这基本上是选择性地传递要写入的内容进入一个结构,但没有结构拥有它。我读到了 Box 类型,这也可能是相关的?)

解决方法

如您所知,基于您已经将 &mut 用于 out。使用 as_ref() 的问题在于它返回一个不可变的引用。相反,您需要使用 as_mut()

pub fn print_number(&mut self,i: isize) {
    if self.out.is_some() {
        writeln!(self.out.as_mut().unwrap(),"The number is {}",i).unwrap()
    }
}

或者,您也可以使用 if let 简化并更地道地表达它:

pub fn print_number(&mut self,i: isize) {
    if let Some(out) = &mut self.out {
        writeln!(out,i).unwrap()
    }
}

我还建议您不要解包,而是返回 io::Result 并让调用者处理任何潜在错误。

pub fn print_number(&mut self,i: isize) -> std::io::Result<()> {
    if let Some(out) = &mut self.out {
        writeln!(out,i)?;
    }
    Ok(())
}

您还可以简化路径,例如std::io::Writestd::io::Result<()>,通过使用 use declaration 导入它们,例如use std::io::{self,Write};,然后将它们更改为 Writeio::Result<()>

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。