首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用静态Fn函数初始化FnMut成员变量

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

Stack Overflow用户
提问于 2019-09-12 11:36:31
回答 2查看 279关注 0票数 1

问题描述

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

现行守则

代码语言:javascript
复制
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);
}
代码语言:javascript
复制
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}`

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

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

  • 用闭包初始化它:callback: &|_: &str|{}
  • 使用成员函数而不是全局函数
  • 创建可变引用:callback: &mut default_fn (原因:cannot return value referencing temporary value)

我的想法不多了,任何帮助都是值得感激的。即使答案是,我试图做的是不可能的原因,我还没有意识到。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-09-12 11:45:29

你真的应该把特征对象函数框起来。这使得整个代码更易于使用:

代码语言:javascript
复制
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);
}

注意,在惯用锈蚀中很难使用回调。我甚至会说他们一点也不习惯。您应该使用频道,类似于:

代码语言:javascript
复制
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());
}
票数 3
EN

Stack Overflow用户

发布于 2019-09-12 12:17:55

我只想分享我找到的解决方案:单线程的,基于回调的。

虽然在我看来,这个问题确实回答了我的问题,但我认为你们对于我将来可能遇到的这种编程风格的问题仍然是正确的。我一定会重新考虑你关于使用频道的建议。

代码语言:javascript
复制
struct Config<'a>{
    callback: Option<&'a mut dyn (FnMut(&str))>
}

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

    pub fn set_callback(mut self, callback_fn: &'a mut dyn (FnMut(&str))) -> Config<'a> {
        self.callback = Some(callback_fn);
        self
    }

    pub fn run_callback(&mut self, msg: &str){
        if let Some(callback) = &mut self.callback{
            callback(msg);
        } else {
            // Default code
            println!("default_fn({})", msg);
        }
    }
}

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.run_callback("Hello World!");

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

    // Demonstration that the callback actually works
    println!("{:?}", msg_log);
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57905873

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档