son sirven sintaxis respectiva que página para ocurre navegador llaman las indica fin etiquetas etiqueta cuales coloca cierre cierra rust

rust - sirven - Función de oxidación que devuelve un cierre: `` se requiere un límite de vida útil explícito ''''



que so las etiquetas html (2)

El siguiente código no compila.

fn main() { let foo = bar(8); println!("Trying `foo` with 4: {:d}", foo(4)); println!("Trying `foo` with 8: {:d}", foo(8)); println!("Trying `foo` with 13: {:d}", foo(13)); } // fn bar(x: int) -> (|int| -> int) { |n: int| -> int { if n < x { return n } x } }

El error es el siguiente.

11:32 error: explicit lifetime bound required .../hello/src/main.rs:11 fn bar(x: int) -> (|int| -> int) { ^~~~~~~~~~~~

Estoy pasando el argumento entero a la bar por valor. ¿Por qué a Rust le importa la vida útil de un entero pasado por valor? ¿Cuál es la forma correcta de escribir tal función que devuelve un cierre? Gracias.

EDITAR

Encontré lo siguiente en el manual. In the simplest and least-expensive form (analogous to a || { } expression), the lambda expression captures its environment by reference, effectively borrowing pointers to all outer variables mentioned inside the function. Alternately, the compiler may infer that a lambda expression should copy or move values (depending on their type.) from the environment into the lambda expression''s captured environment.

¿Hay alguna otra especificación de cómo el compilador deduce si capturar las variables externas por referencia, copiarlas o moverlas? ¿Cuáles son los criterios de evaluación y cuál es su orden de aplicación? ¿Está esto documentado (si no se lee el código del compilador)?


¿Hay alguna otra especificación de cómo el compilador deduce si capturar las variables externas por referencia, copiarlas o moverlas? ¿Cuáles son los criterios de evaluación y cuál es su orden de aplicación? ¿Está esto documentado (si no se lee el código del compilador)?

Permítanme complementar la respuesta de Francisco:

Cierres como |x| a*x+b |x| a*x+b siempre capturan su entorno (como a y b aquí) por referencia. En su caso, estas son variables de función local y Rust le impide devolver dicho cierre porque estas variables de función local ya no existirían. Agradezcamos al prestamista por detectar este error. Los casos de uso para estos cierres normalmente los pasan como parámetros a otras funciones, no devolviéndolos. Sin embargo, si no accede a ninguna otra variable, dicho cierre puede sobrevivir al alcance de la función en la que se creó: ||:''static -> SomeType . La representación de estos cierres es solo un par de punteros. Uno que apunta a la función y otro que apunta al marco de la pila de la función (si algo fue capturado por referencia).

Los cierres que se escriben con proc siempre capturan su entorno "adquiriéndolos" (se mueven al estado del objeto de cierre). Otra propiedad de este tipo de cierres es que solo puede invocarlos una vez porque la función asociada realmente consume el estado del cierre. Esto es útil para iniciar tareas concurrentes. proc cierres de proc incure un costo de asignación de montón porque almacenan su estado indirectamente (similar a lo que hace Box ). La ventaja de esto es que la representación de cierres de proceso (ignorando el estado encuadrado) es solo un par de punteros. Un puntero a la función y un puntero a las variables en caja.

Luego, hay los llamados cierres sin caja. Hasta donde yo sé, los cierres sin caja aún se consideran experimentales. Pero te permiten hacer exactamente lo que quieres, no directamente, sino cuando estás en la caja. Los cierres sin caja también capturan su entorno por valor. Pero a diferencia de los cierres de proc , no hay una asignación de montón involucrada. Almacenan sus variables directamente. Puedes pensar en ellos como una estructura con un tipo único e irrevocable que implementa uno de los siguientes rasgos: Fn , FnMut o FnOnce con un único método que toma su parámetro propio como &self , &mut self o self respectivly. Los cierres no compartidos son buenos ya que carecen del nivel de indirección para la función y las variables que permiten una mejor alineación y, por lo tanto, un mejor rendimiento. Pero actualmente no es posible escribir una función que devuelva directamente dicho cierre sin caja. Una solución es guardar el cierre sin caja como lo mostró Francis en la última sección de esta respuesta.


EDITAR: i32 int con i32 , porque int ahora está en desuso. Ha sido reemplazado por isize , pero probablemente no sea del tipo correcto.

El compilador no se queja del parámetro del cierre; se está quejando del cierre en sí. Debe especificar una duración para el cierre.

fn bar<''a>(x: i32) -> (|i32|:''a -> i32) { |n: i32| -> i32 { if n < x { return n } x } }

Pero no funciona:

<anon>:13:16: 13:17 error: captured variable `x` does not outlive the enclosing closure <anon>:13 if n < x { return n } ^ <anon>:11:41: 17:2 note: captured variable is valid for the block at 11:40 <anon>:11 fn bar<''a>(x: i32) -> (|i32|:''a -> i32) { <anon>:12 |n: i32| -> i32 { <anon>:13 if n < x { return n } <anon>:14 <anon>:15 x <anon>:16 } ... <anon>:11:41: 17:2 note: closure is valid for the lifetime ''a as defined on the block at 11:40 <anon>:11 fn bar<''a>(x: i32) -> (|i32|:''a -> i32) { <anon>:12 |n: i32| -> i32 { <anon>:13 if n < x { return n } <anon>:14 <anon>:15 x <anon>:16 } ...

Esto se debe a que el cierre intenta capturar x por referencia, pero el cierre sobrevive x , que es ilegal (de la misma manera sería ilegal devolver una referencia a x ).

Probemos usando un proc Un proc captura valores por movimiento.

EDIT: proc se ha eliminado del idioma desde que se escribió originalmente esta respuesta.

fn main() { let foo = bar(8); println!("Trying `foo` with 4: {:d}", foo(4)); println!("Trying `foo` with 8: {:d}", foo(8)); println!("Trying `foo` with 13: {:d}", foo(13)); } // fn bar<''a>(x: i32) -> (proc(i32):''a -> i32) { proc(n: i32) -> i32 { if n < x { return n } x } }

Desafortunadamente, eso tampoco funciona.

<anon>:5:43: 5:46 error: use of moved value: `foo` <anon>:5 println!("Trying `foo` with 8: {:d}", foo(8)); ^~~ note: in expansion of format_args! <std macros>:2:23: 2:77 note: expansion site <std macros>:1:1: 3:2 note: in expansion of println! <anon>:5:5: 5:51 note: expansion site <anon>:4:43: 4:46 note: `foo` moved here because it has type `proc(i32) -> i32`, which is non-copyable (perhaps you meant to use clone()?) <anon>:4 println!("Trying `foo` with 4: {:d}", foo(4)); ^~~

Solo puedes llamar a un proc una vez. La llamada consume el cierre.

La solución correcta ahora es usar cierres "sin caja":

fn main() { let foo = bar(8); println!("Trying `foo` with 4: {}", foo(4)); println!("Trying `foo` with 8: {}", foo(8)); println!("Trying `foo` with 13: {}", foo(13)); } // fn bar(x: i32) -> Box<Fn(i32) -> i32 + ''static> { Box::new(move |&: n: i32| -> i32 { if n < x { return n } x }) }

Salida:

Trying `foo` with 4: 4 Trying `foo` with 8: 8 Trying `foo` with 13: 8