我想知道rust是否可以自动将实现Fn(&X) -> Y
的函数强制转换为实现Fn(X) -> Y
的函数
fn do_stuff<Y, F: Fn(i32) -> Y>(action: F) {
// Does some stuff with the method (specifically, move it into a Box)
}
,我想这样命名它:
do_stuff(i32::to_string)
代替当前
do_stuff(|x| x.to_string())
然而,我得到以下错误:
期望函数签名
fn(i32) -> _
,发现函数签名
for<'r> fn(&'r i32) -> _
.
我认为这是因为函数i32::to_string
借用了&self
作为参数,而闭包则拥有了它的所有权。
是否有办法改变do_stuff
的签名,使我也可以这样调用它?
这里是rust游乐场问题的再现。
没有办法将Fn(&T) -> U
隐式强制转换为Fn(T) -> U
,因为它不属于Rust所允许的隐式强制。但是,有一种方法可以剔除重复代码:
fn add_ref<T, U>(f: impl Fn(&T) -> U) -> impl Fn(T) -> U {
move |ref x| f(x)
}
它适用于(最小化版本)您的示例:
fn do_stuff<Y, F: Fn(i32) -> Y>(_: F) {}
fn main() {
do_stuff(add_ref(i32::to_string))
// do_stuff(i32::to_string)
// ^^^^^^^^^^^^^^^^^^^^^^^^ this would fail
}
看操场
从技术上讲,这是可行的:
use std::borrow::Borrow;
fn do_stuff<X, Y, F: Fn(X) -> Y>(action: F)
where
X: Borrow<i32>,
{
// Does some stuff with the method (specifically, move it into a Box)
}
fn bla(x: i32) {}
fn bla_ref(x: &i32) {}
fn main() {
do_stuff(i32::to_string);
do_stuff(bla);
do_stuff(bla_ref);
}
虽然经常使用|x| x.do_something()
闭包是很正常的,所以我不会太担心它。