keywords - En Rust, ¿cómo se pasa una función como parámetro?
meta title y meta descripcion (2)
¿Puedo pasar una función como parámetro en Rust (probablemente sí), si esto es posible como puedo hacerlo?
Si no puedes, que es una buena alternativa.
He intentado alguna sintaxis pero no he conseguido
sé que puedo hacerlo
..//
let fun: fn(value: i32) -> i32;
fun = funTest;
fun(5i32);
..//
fn funTest(value: i32) -> i32 {
println!("{}", value);
value
}
pero no como pasar la función como un parámetro a otra función
..//
fn funTest(value: i32, (some_function_prototype)) -> i32 {
println!("{}", value);
value
}
Seguro que puede:
fn funTest(value: i32, f: &Fn(i32) -> i32) -> i32 {
println!("{}", f(value));
value
}
fn times2(value: i32) -> i32 {
2 * value
}
fn main() {
funTest(5, ×2);
}
Pero esto es Rust, por lo que debe tener en cuenta la propiedad y la vida útil del cierre .
TL; DR; Básicamente hay 3 tipos de cierres (objetos que se pueden llamar):
-
Fn
: El más genérico, es una función pura. -
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.
Si está utilizando un simple cierre de puntero a función, entonces el conjunto de captura está vacío y tiene el sabor Fn
.
Si quieres hacer cosas más sofisticadas, tendrás que usar las funciones lambda.
ACTUALIZACIÓN : Después de un tiempo más de aprendizaje de Rust, necesito la necesidad de corregir un poco esta respuesta.
En Rust hay punteros a funciones adecuados, que funcionan como los de C. Su tipo es, por ejemplo, fn(i32) -> i32
. El Fn(i32) -> i32
FnMut(i32) -> i32
, FnMut(i32) -> i32
FnOnce(i32) -> i32
y FnOnce(i32) -> i32
son realmente rasgos. Obviamente, un puntero a función siempre implementa los tres, pero Rust también tiene cierres, que pueden o no convertirse a punteros (dependiendo de si el conjunto de captura está vacío) a las funciones, pero implementan algunos de estos rasgos.
Así, por ejemplo, el ejemplo anterior se puede expandir (y corregir el estilo un poco):
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;
//static dispatch
fun_test_impl(5, times2);
fun_test_impl(5, |x| 2*x);
fun_test_impl(5, |x| y*x);
//dynamic dispatch
fun_test_dyn(5, ×2);
fun_test_dyn(5, &|x| 2*x);
fun_test_dyn(5, &|x| y*x);
//C-like pointer to function
fun_test_ptr(5, times2);
fun_test_ptr(5, |x| 2*x); //ok: empty capture set
fun_test_ptr(5, |x| y*x); //error: expected fn pointer, found closure
}
Fn
, FnMut
y FnOnce
, que se describen en la otra respuesta, son tipos de cierre . Los tipos de funciones que cierran sobre su alcance.
Además de pasar cierres, Rust también admite el paso de funciones simples (sin cierre), como esto:
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) -> i32
aquí es un tipo de puntero de función .
Si no necesita un cierre completo, trabajar con tipos de funciones a menudo es más simple, ya que no tiene que lidiar con esas sutilezas de por vida.