es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

¿Por qué el verificador de préstamo de Rust no puede aprovechar los límites de `’static`?

Considera el siguiente programa Rust:

#![feature(generic_associated_types)]

pub trait Func {
    type Input<'a>;
    type Output;

    fn call(self, input: Self::Input<'_>) -> Self::Output;
}

fn invoke<'cx, F>(f: F, ctx: &'cx mut u8)
    where F: 'static + Func<input<'cx> = &'cx u8, Output = u8>,
{
    let input = &*ctx;
    let out = f.call(input);
    *ctx = out;
}

He utilizado #![feature(generic_associated_types)], pero creo que la pregunta que estoy haciendo sigue siendo relevante si mueves 'a de Func::Input a Func y utilizas un límite de rasgo de rango superior en invoke.

Este código genera errores, pero no creo que sea incorrecto:

error[E0506]: cannot assign to `*ctx` because it is borrowed
  --> src/lib.rs:15:5
   |
10 | fn invoke<'cx, F>(f: F, ctx: &'cx mut u8)
   |         --- lifetime `'cx` defined here
...
13 |     let input = &*ctx;
   |                 ----- borrow of `*ctx` occurs here
14 |     let out = f.call(input);
   |               ------------- argument requires that `*ctx` is borrowed for `'cx`
15 |     *ctx = out;
   |     ^^^^^^^^^^ assignment to borrowed `*ctx` occurs here

Primero, ctx se referencea de nuevo como input, que se pasa a f.call y luego nunca se utiliza de nuevo. f.call devuelve un valor que no contiene ninguna lifetime (u8: 'static), por lo que no hay ninguna conexión entre out y ctx.

De la misma manera, el tipo de f no contiene ninguna lifetime (F: 'static), por lo que no puede contener una referencia con lifetime 'cx. Además, la lifetime 'cx no se puede convertir de forma segura a 'static dentro de call, por lo que no hay forma de “sacar” una referencia con esa lifetime que sea accesible más allá de la invocación de f.call. Por lo tanto, no veo cómo algo puede hacer referencia a ctx, y creo que asignarle un valor en la última línea debería ser válido.

¿Me estoy perdiendo algo? ¿Aceptar este código sería incorrecto? Si no, ¿por qué Rust no aprovecha los límites de 'static de esta manera?</input<‘cx>

Tags:  ,

Answer

  1. Avatar for davy.ai

    El código en cuestión tiene un error relacionado con el comprobador de préstamos (“borrow-checker”), pero no es inseguro. El error ocurre porque se toma prestado ctx para crear input, que luego se utiliza como argumento en f.call. Sin embargo, después de que f.call retorna, el préstamo de ctx ya no es necesario y out no tiene conexión con ctx. Entonces, en teoría, asignar a ctx en la última línea debería ser seguro.

    Sin embargo, el comprobador de préstamos de Rust está diseñado para ser conservador y prevenir ciertos tipos de inseguridad, incluso si eso significa no permitir algún código seguro. En este caso, el comprobador de préstamos no tiene en cuenta actualmente el hecho de que el tipo de f no contiene duraciones de vida (lifetimes), y por lo tanto no puede contener una referencia con duración de vida 'cx. Como resultado, el comprobador de préstamos asume que ctx podría ser referenciado por f.call, aunque en realidad no puede, y emite un error.

    Aceptar este código no sería inseguro, pero requeriría cambios en el comprobador de préstamos para tener en cuenta los tipos con límites de 'static. Actualmente, esto no es posible debido a limitaciones técnicas, pero es un área posible para futuras mejoras.

Comments are closed.