rust - que - sucesiones convergentes y divergentes ejercicios resueltos
¿Por qué usaría funciones divergentes? (2)
Al leer el libro de Rust, encontré un tema interesante : funciones divergentes :
Rust tiene una sintaxis especial para "funciones divergentes", que son funciones que no devuelven:
fn diverges() -> ! { panic!("This function never returns!"); }
Una función divergente puede ser utilizada como cualquier tipo:
let x: i32 = diverges(); let x: String = diverges();
¿Cuáles serían los casos de uso de una función divergente? El libro dice que
panic!()
hace que el hilo de ejecución actual se bloquee con el mensaje dado. Debido a que esta función causará un bloqueo, nunca regresará, ¡y por lo tanto tiene el tipo!
Eso tiene sentido, pero no puedo pensar en dónde más podría ser útil una función divergente, ¡y parece que está muy localizado para el panic!
. Sé que debe haber algunos escenarios útiles para explicar por qué introdujeron funciones divergentes. ¿Dónde es probable que vea funciones divergentes en Rust?
Como citó en el libro, el tipo de fondo de Rust se usa para especificar funciones que no regresan. Esto incluye:
-
panic!()
- bucle para siempre
- salir del programa (excepto regresar de
main()
), como exit() , cuya firma espub fn exit(code: i32) -> !
Tiene varios usos. Puede utilizarse para funciones diseñadas para entrar en pánico o salir del programa. panic!()
sí es una de esas funciones, pero también puede aplicarse a funciones que envuelven panic!()
, como imprimir información de error más detallada y luego entrar en pánico.
También se puede utilizar para funciones que nunca regresan. Si una función entra en un bucle infinito, como el bucle principal de un servidor, y por lo tanto nunca regresa, podría definirse de esta manera.
Otro uso posible sería una envoltura alrededor de la familia de funciones exec
Unix, en la cual el proceso actual se reemplaza con el que se está ejecutando.
Es útil tener un tipo así porque es compatible con todos los otros tipos. Para que el tipo sea seguro, Rust debe garantizar que todas las ramas de una match
o if
declaración devuelve el mismo tipo. Pero si hay algunas ramas que no están disponibles o que indican un error, necesita alguna forma de lanzar un error que se unifique con el tipo devuelto por las otras ramas. Porque !
Unifica con todos los tipos, puede ser utilizado en cualquier caso.
Hay un RFC interesante (y discussion ) en el momento que argumenta (en parte) por expandir los lugares donde !
se puede usar , argumentando que debe tratarse como un tipo completo como ()
es; !
siendo un tipo sin valores que se unifica con todos los demás tipos, mientras que ()
es un tipo distinto con un solo valor. No estoy seguro de estar de acuerdo con el RFC completo, ¡pero la discusión sobre el tratamiento !
como un tipo completo es interesante y creo que podría proponerse por separado del resto del RFC.
Actualización : Desde que escribí lo anterior, ¡la parte del RFC sobre la promoción !
a un tipo completo se dividió en un RFC separado y se fusionó , y está en proceso de implementación (actualmente disponible en versiones nocturnas detrás de una puerta de características). Como tipo completo, se puede usar en más contextos, como en Result<T, !>
indica un resultado que nunca puede fallar, o Result<!, E>
como uno que nunca puede tener éxito. Estos son útiles en contextos genéricos; Si tiene algún rasgo que requiere un método para devolver un resultado, pero para esa implementación en particular solo puede tener éxito, no necesita completar algún tipo de error ficticio.