[Solved] Is there a way to pass a method to a function?

#1

I’m trying to use an external crate’s (logwatch) function that takes a callback function as input. Here’s the sig:

pub fn watch<F: ?Sized>(&mut self, callback: &F)
where
    F: Fn(String),

It works but my (lame) attempts to modify external data with it have failed. Here’s my last attempt on the playground.

I’ll probably end up implementing the external lib’s functionality myself, but was wondering if there was a way to make this work?

#2

Eta expand it.

extern_lib_func(&|s| d.update(s));

Also, you need FnMut instead since the closure mutates d.

#3

You have to wrap it |s| d.update(s), but as callback is of Fn, it can’t change anything, you need to make callback of FnMut to have it working. Also some other things need to be marked as mut:

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=5d0e4826d983aa404ddf1f5a63f12b44

#4

Well, it seems like they’re working with an external crate that is expecting the &Fn (which is a bit odd). If the signature of extern_lib_func isn’t negotiable, then they need to use RefCell:

let d = RefCell::new(Data::new());

extern_lib_func(&|msg| d.borrow_mut().update(msg));

Playground

I’m surprised the bound on callback isn’t also Sync. If the callback might be used on multiple threads, then they’ll need a Mutex instead of a RefCell.

1 Like
#5

Yep, that was it. One of my attempts did use an Eta expansion, but the RefCell escaped by me. Oh well, thanks for the quick help. I love this community.

#6

I doubt this was your intent, but this word can be insulting to people with disabilities, so in the spirit of fostering an inclusive community, it’s better to avoid it.

#7

@baumanj Yes, it wasn’t my intention. Apologies. Won’t happen again.

1 Like