una sintactico simple semantico oraciones oracion morfologico morfologicas morfologicamente hace ejercicios ejemplos como analizadas analisis rust

rust - sintactico - como se hace un analisis morfologico



¿Cómo se diferencia la sintaxis<> de un límite de por vida normal? (1)

for<> sintaxis se denomina límite de caracteres de rango superior (HRTB), y de hecho se introdujo principalmente debido a los cierres.

En resumen, la diferencia entre foo y bar es que en foo() la duración de la referencia de usize interno es proporcionada por el llamador de la función, mientras que en bar() la función proporciona la misma duración. Y esta distinción es muy importante para la implementación de foo / bar .

Sin embargo, en este caso particular, cuando Trait no tiene métodos que usen el parámetro tipo, esta distinción no tiene sentido, así que imaginemos que Trait ve así:

trait Trait<T> { fn do_something(&self, value: T); }

Recuerde, los parámetros de por vida son muy similares a los parámetros de tipo genérico. Cuando utiliza una función genérica, siempre especifica todos sus parámetros de tipo, proporcionando tipos concretos, y el compilador monomorfiza la función. Lo mismo ocurre con los parámetros de por vida: cuando llama a una función que tiene un parámetro de por vida, especifica la duración, aunque implícitamente:

// imaginary explicit syntax // also assume that there is TraitImpl::new::<T>() -> TraitImpl<T>, // and TraitImpl<T>: Trait<T> ''a: { foo::<''a>(Box::new(TraitImpl::new::<&''a usize>())); }

Y ahora hay una restricción sobre lo que foo() puede hacer con este valor, es decir, con qué argumentos puede llamar do_something() . Por ejemplo, esto no compilará:

fn foo<''a>(b: Box<Trait<&''a usize>>) { let x: usize = 10; b.do_something(&x); }

Esto no se compilará porque las variables locales tienen vidas que son estrictamente más pequeñas que las vidas especificadas por los parámetros de duración (creo que está claro por qué es así), por lo tanto, no se puede invocar b.do_something(&x) porque requiere su argumento tener vida ''a , que es estrictamente mayor que la de x .

Sin embargo, puedes hacer esto con la bar :

fn bar(b: Box<for<''a> Trait<&''a usize>>) { let x: usize = 10; b.do_something(&x); }

Esto funciona porque ahora la bar puede seleccionar la vida útil necesaria en lugar de la persona que llama de la bar .

Esto sí importa cuando utiliza cierres que aceptan referencias. Por ejemplo, supongamos que desea escribir un método de filter() en la Option<T> :

impl<T> Option<T> { fn filter<F>(self, f: F) -> Option<T> where F: FnOnce(&T) -> bool { match self { Some(value) => if f(&value) { Some(value) } else { None } None => None } } }

El cierre aquí debe aceptar una referencia a T porque de lo contrario sería imposible devolver el valor contenido en la opción (este es el mismo razonamiento que con filter() en los iteradores).

Pero, ¿qué duración debería tener &T en FnOnce(&T) -> bool ? Recuerde, no especificamos tiempos de vida en las firmas de función solo porque hay una elisión de por vida en su lugar; en realidad, el compilador inserta un parámetro de por vida para cada referencia dentro de una firma de función. Debería haber algún tiempo de vida asociado con &T en FnOnce(&T) -> bool . Entonces, la forma más "obvia" de expandir la firma anterior sería esta:

fn filter<''a, F>(self, f: F) -> Option<T> where F: FnOnce(&''a T) -> bool

Sin embargo, esto no va a funcionar. Como en el ejemplo de Trait anterior, el ciclo ''a vida es estrictamente más largo que el tiempo de vida de cualquier variable local en esta función, incluido el value dentro de la declaración de coincidencia. Por lo tanto, no es posible aplicar f to &value debido a una incompatibilidad de por vida. La función anterior escrita con dicha firma no se compilará.

Por otro lado, si ampliamos la firma de filter() esta manera (y así es como ahora funciona el elision de por vida para cierres en Rust):

fn filter<F>(self, f: F) -> Option<T> where F: for<''a> FnOnce(&''a T) -> bool

entonces, llamar f con &value como argumento es perfectamente válido: ahora podemos elegir el tiempo de vida, por lo que usar la vida útil de una variable local es absolutamente correcto. Y es por eso que los HRTB son importantes: no podrás expresar muchos patrones útiles sin ellos.

También puede leer otra explicación de HRTB en Nomicon .

Considera el siguiente código:

trait Trait<T> {} fn foo<''a>(_b: Box<Trait<&''a usize>>) {} fn bar(_b: Box<for<''a> Trait<&''a usize>>) {}

Ambas funciones, foo y bar parecen aceptar un Box<Trait<&''a usize>> , aunque foo hace de forma más concisa que bar . ¿Cuál es la diferencia entre ellos?

Además, ¿en qué situaciones necesitaría for<> sintaxis for<> como la anterior? Sé que la biblioteca estándar de Rust lo usa internamente (a menudo relacionado con cierres), pero ¿por qué mi código podría necesitarlo?