Consider a certain API that is designed as follows:
pub fn update<F>(f:F) where F:FnOnce(i32){/* ... */}
Besides using closure to capture the environment variable, is there any way to construct a customized data structure that is callable in the stable version of Rust? Something like this:
struct Callable{
data: Data,
}
update(Callable{data:Data{/* ... */}});
no.
the "unsugared" FnOnce trait is not stable, and I don't think it will be stablized soon (or ever).
in some cases, you can use a custom trait and a blanket implementation as a workaround, but you don't really call the value like a closure, you'll have to use a regular trait methods:
trait MyFnOnceI32 {
type Output;
fn call_once(self, arg: i32) -> Self::Output;
}
impl<F, R> MyFnOnceI32 for F where F: FnOnce(i32) -> R {
type Output = R;
fn call_once(self, arg: i32) -> R {
self(arg)
}
}
pub fn update<F>(f: F) where F: MyFnOnceI32<Output = ()> {
f.call_once(42);
}
struct Callable {
data: Data
}
impl MyFnOnceI32 for Callable {
type Output = ();
fn call_once(self, arg: i32) {
todo!()
}
}
update(|x: i32| do_something());
update(Callable{ data: Data {}});
see also the fn-traits crate.
1 Like
However, this approach is based on I can control the signature of update, but it's not possible because update is in the upstream crate.
yeah, that's what I meant by "in some cases".
anyways, I don't know the reason you didn't want to use a closure in the first place, but you can also make an adapter for the custom callback trait by simply wrapping it in a closure:
fn into_closure<F>(f: F) -> impl FnOnce(i32)
where F: MyFnOnceI32<Output = ()>
{
move |arg| f.call_once(arg)
}
update(into_closure(Callable { data: Data {} }));
or, equivalently, create a wrapper for update():
fn my_update<F: MyFnOnceI32<Output=()>>(f: F) {
update(|arg| f.call_once(arg))
}