rust - 使用静态 Fn 函数初始化 FnMut 成员变量

标签 rust

问题描述

我有一个 Config 结构,可以存储一个 FnMut 回调函数。问题是:并非我的所有配置都需要回调函数,因此我想将添加回调函数设为可选。这需要使用默认函数初始化成员变量,如果没有设置回调,该函数将被使用。

现有代码

struct Config<'a>{
    callback: &'a mut dyn (FnMut(&str))
}

fn default_fn(msg: &str){
    println!("default_fn({})", msg);
}

impl<'a> Config<'a> {
    pub fn new() -> Config<'a> {
        Config{
            callback: &default_fn // ERROR: types differ in mutability
        }
    }
    
    pub fn set_callback(mut self, callback_fn: &'a mut dyn (FnMut(&str))) -> Config<'a> {
        self.callback = callback_fn;
        self
    }
}

fn main() {
    // Our FnMut callback
    let mut msg_log: Vec<String> = vec![];
    let mut callback_fn = |msg: &str| {
        msg_log.push(msg.to_string());
    };
    
    {
        let mut config = Config::new();
        (config.callback)("Hello World!");
        
        config = config.set_callback(&mut callback_fn);
        (config.callback)("Hello World!");
    }
    
    // Demonstration that the callback actually works
    println!("{:?}", msg_log);
}
error[E0308]: mismatched types
  --> src/main.rs:13:23
   |
13 |             callback: &default_fn // ERROR: types differ in mutability
   |                       ^^^^^^^^^^^ types differ in mutability
   |
   = note: expected type `&mut dyn for<'r> std::ops::FnMut(&'r str)`
              found type `&for<'r> fn(&'r str) {default_fn}`

有人对如何解决这个问题有什么建议吗?

我已经尝试过,但没有成功:

  • 使用闭包对其进行初始化:回调:&|_: &str|{}
  • 使用成员函数而不是全局函数
  • 创建可变引用:回调:&mut default_fn (原因:无法返回引用临时值的值)

我的想法已经用完了,感谢任何帮助。即使答案是由于我尚未意识到的原因,我正在尝试做的事情是不可能的。

最佳答案

你真的应该把 trait 对象函数装箱。这使得整个代码更易于使用:

struct Config<'a>{
    callback: Box<dyn FnMut(&str) + 'a>,
}

fn default_fn(msg: &str){
    println!("default_fn({})", msg);
}

impl<'a> Config<'a> {
    pub fn new() -> Config<'a> {
        Config{
            callback: Box::new(default_fn)
        }
    }

    pub fn set_callback(self, callback: &'a mut dyn (FnMut(&str))) -> Config<'a> {
        Config {
            callback: Box::new(callback),
            ..self
        }
    }
}

fn main() {
    // Our FnMut callback
    let mut msg_log = vec![];
    let mut callback_fn = |msg: &str| {
        msg_log.push(msg.to_string());
    };

    {
        let mut config = Config::new();
        (config.callback)("Hello World!");

        config = config.set_callback(&mut callback_fn);
        (config.callback)("Hello World!");
    }

    // Demonstration that the callback actually works
    println!("{:?}", msg_log);
}

请注意,在惯用的 Rust 中很难使用回调。我什至会说它们根本不是惯用语。你应该使用 channel , 类似这样的东西:

use std::sync::mpsc::{channel, Sender, SendError};

struct Config {
    sender: Sender<String>,
}

impl Config {
    pub fn new(sender: Sender<String>) -> Config {
        Config{
            sender
        }
    }

    pub fn send(&self, message: String) -> Result<(), SendError<String>> {
        self.sender.send(message)
    }
}

fn main() {
    let (sender, receiver) = channel();

    let config = Config::new(sender);
    config.send("Hello world!".into()).unwrap();

    println!("{:?}", receiver.recv().unwrap());
}

关于rust - 使用静态 Fn 函数初始化 FnMut 成员变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57905873/

相关文章:

types - 我如何在 Rust 中打印变量的类型?

windows - 路径::read_dir和Windows

rust - 为什么完全静态的 Rust ELF 二进制文件有全局偏移表 (GOT) 部分?

rust - 在 Rust 的结构中查找最常出现的字符串?

rust - 如何使用 cargo 设置环境变量?

file-io - 如何使多个迭代器可以处理与文件有关的相同数据?

Rust 最小编译程序大小

rust - 是否可以为异步函数创建类型别名?

rust - 如何将网站内容下载到字符串中?

compiler-errors - 为什么我不能将 main.rs 添加到 crate 的源代码并导入结构?