Seguro que puede:
fn fun_test(value: i32, f: &dyn Fn(i32) -> i32) -> i32 {
println!("{}", f(value));
value
}
fn times2(value: i32) -> i32 {
2 * value
}
fn main() {
fun_test(5, ×2);
}
Como se trata de Rust, debe tener en cuenta la propiedad y la vida útil del cierre .
TL; DR; Básicamente, existen 3 tipos de cierres (objetos invocables):
Fn: No puede modificar los objetos que captura.
FnMut: Puede modificar los objetos que captura.
FnOnce: El más restringido. Solo se puede llamar una vez porque cuando se llama se consume a sí mismo y sus capturas.
Consulte ¿ Cuándo implementa un cierre Fn, FnMut y FnOnce? para más detalles
Si está utilizando un cierre simple de puntero a función, entonces el conjunto de captura está vacío y tiene el Fnsabor.
Si quieres hacer cosas más sofisticadas, entonces tendrás que usar funciones lambda.
En Rust hay punteros adecuados para funciones, que funcionan igual que los de C. Su tipo es, por ejemplo fn(i32) -> i32. El Fn(i32) -> i32, FnMut(i32) -> i32y FnOnce(i32) -> i32en realidad son rasgos. Un puntero a una función siempre implementa los tres, pero Rust también tiene cierres, que pueden o no convertirse en punteros (dependiendo de si el conjunto de captura está vacío) a funciones, pero implementan algunos de estos rasgos.
Entonces, por ejemplo, el ejemplo anterior se puede expandir:
fn fun_test_impl(value: i32, f: impl Fn(i32) -> i32) -> i32 {
println!("{}", f(value));
value
}
fn fun_test_dyn(value: i32, f: &dyn Fn(i32) -> i32) -> i32 {
println!("{}", f(value));
value
}
fn fun_test_ptr(value: i32, f: fn(i32) -> i32) -> i32 {
println!("{}", f(value));
value
}
fn times2(value: i32) -> i32 {
2 * value
}
fn main() {
let y = 2;
fun_test_impl(5, times2);
fun_test_impl(5, |x| 2*x);
fun_test_impl(5, |x| y*x);
fun_test_dyn(5, ×2);
fun_test_dyn(5, &|x| 2*x);
fun_test_dyn(5, &|x| y*x);
fun_test_ptr(5, times2);
fun_test_ptr(5, |x| 2*x);
fun_test_ptr(5, |x| y*x);
}
Fn*son rasgos, por lo que se aplica el<T: Trait>vs habitual(t: &T). La principal limitación de la solución no genérica es que debe usarse con referencias. Entonces, si lo deseaFnOnce, lo que debe pasar como una copia, debe usar el estilo genérico.<F: Fn..>lugar de(f: &Fn...). Y esto es por una razón: los genéricos darán como resultado un envío estático, mientras que los objetos de rasgo requieren un envío dinámico.FnOncees en realidad el rasgo más genérico: acepta todos los cierres independientemente de si leen, modifican o toman posesión del estado capturado.FnMutes más restrictivo, no acepta cierres que se apropien de un objeto capturado (pero aún permite modificaciones de estado).Fnes el más restrictivo porque no acepta cierres que modifiquen su estado capturado. Por lo tanto, requerir&Fncoloca la mayor restricción para lafunTestpersona que llama, al tiempo que proporciona la menor restricción sobre cómofse puede invocar dentro de ella.Fn,FnMutYFnOnce, se indica en la otra respuesta, son de cierre tipos. Los tipos de funciones que se cierran sobre su alcance.Además de pasar cierres, Rust también admite pasar funciones simples (sin cierre), como esta:
fn times2(value: i32) -> i32 { 2 * value } fn fun_test(value: i32, f: fn(i32) -> i32) -> i32 { println!("{}", f (value)); value } fn main() { fun_test (2, times2); }fn(i32) -> i32aquí hay un tipo de puntero de función .Si no necesita un cierre completo, trabajar con tipos de funciones suele ser más sencillo, ya que no tiene que lidiar con esas bondades de por vida del cierre.
fuente