In pratica, la ragione # 1 dovrete scrivere annotazioni a vita è a leggere perché il compilatore ti chiede così. Rifiuterà le firme delle funzioni che non sono coperte da lifetime elision rules.
Suppongo che ti piacerebbe un semplice esempio in cui le vite sono obbligatorie. Immaginate il seguente scenario:
struct Blah<'a> {
hoy: &'a u8
}
fn want_a_hoy(blah: &Blah) -> &u8 {
blah.hoy
}
L'intenzione è ovvio, ma il compilatore non gestirlo:
<anon>:7:35: 7:38 error: missing lifetime specifier [E0106]
<anon>:7 fn want_a_hoy(blah: &Blah) -> &u8 {
^~~
<anon>:7:35: 7:38 help: see the detailed explanation for E0106
<anon>:7:35: 7:38 help: this function's return type contains a borrowed value, but
the signature does not say which one of `blah`'s 2 elided
lifetimes it is borrowed from
In questo caso, le annotazioni risolvono il problema:
fn want_a_hoy<'a, 'b>(blah: &'b Blah<'a>) -> &'a u8 {
blah.hoy
}
Qui stai specificando 'a
due volte (su Blah<'a>
e &'a
). Questa è la stessa vita! Quindi quello che stai dicendo al compilatore è: "Questa funzione si riferisce a un blah che contiene un riferimento interiore: restituirò qualcosa che vive esattamente come il riferimento interiore del blah". In questo caso, la firma dà un forte suggerimento che è probabile che tu possa restituire qualcosa che proviene dalle viscere del blah.
Un esempio ancora più semplice in cui l'elisione a vita non riesce è 'fn pick_one (a: & T, b: & T) -> & T' (anche se restituisce sempre uno di questi in modo incondizionato). – delnan
ha senso, grazie! –