Capire le vite: la durata massima e 'statica
Il mio processo di apprendimento per la durata della ruggine era simile a questo (basato sul libro sulla ruggine):
- Voglio annotare, quando i valori dietro i riferimenti escono dall'ambito
- Di solito (non sempre! Vedere la sezione .data, cioè 'statico) i valori vivono all'interno di un
{}blocco - Annotiamo blocchi come
't: {…}e, ad esempio, i campi struct ottengono una durata simile&'t identcon lo stesso nome di duratat - Questa comprensione è sbagliata. Perché? Le definizioni del nome del blocco sono molto probabilmente sconosciute all'implementatore della struttura e potrebbero esserci diverse definizioni del nome del blocco per la stessa struttura.
- Quindi la definizione
't: {…}e l'uso&'t identdevono essere completamente indipendenti. - I compilatori possono facilmente determinare le definizioni, quindi gli utenti non devono mai scrivere
't: {…}. I programmatori devono preoccuparsi solo della&'t identparte delle specifiche. - I compilatori potrebbero analizzare i corpi delle funzioni (in caso di
struct: uso dei membri della struttura) e determinare la&'t identparte. - Questa comprensione è sbagliata. Perché? Perché a volte il corpo della funzione (o l'uso dei membri della struttura) non è ancora disponibile (ad esempio, un tratto specifica una funzione, ma l'implementazione viene eseguita da un'altra parte in futuro).
- Di conseguenza,
structefndevono specificare completamente le durate rispettivamente nella definizione della struttura o nella firma della funzione. - Le specifiche seguono principalmente le stesse regole euristiche. Quindi introduciamo l'elisione a vita. Inserisce le durate in base a regole mirate ai casi di utilizzo più comuni e possiamo disattivarli in qualsiasi momento.
A questo punto, penso che la mia comprensione sia abbastanza vicina a come funziona effettivamente. Ma ora, la mia comprensione è sbagliata. Vediamo qualche esempio:
#[derive(Debug)]
struct Stats {
league: &str,
}
const NAME: &str = "rust";
fn more_difficult_league(s1: &Stats, s2: &Stats) -> &str {
if s1.league == s2.league {
s1.league
} else if s1.league == "PHP" {
s2.league
} else {
"C++"
}
}
fn main() {
let mut st = Stats { league: name };
let dleague = more_difficult_league(&st, &st);
println!("{}", dleague);
}
Ovviamente, ho omesso qualsiasi specifica di durata.
La durata dei campi struct è l'intera durata del programma (
'static) o fintanto che la struttura (Stats<'a>conleague: &'a str)In una funzione / metodo, potremmo avere riferimenti con tempi di vita
'a,'b,'c, .... Qual è la durata del valore restituito?- O è un valore statico (
'static) - O è sempre la stessa durata specifica (come
'c) - O è una durata specifica, quale sarà nota in fase di compilazione o esecuzione. Per il compilatore dobbiamo specificare la durata del caso peggiore
max('a, 'b, 'c, …). Per quanto ne so, questo può essere fatto assegnando a ogni riferimento la stessa durata.
- O è un valore statico (
Questo sembra funzionare per la seguente funzione artificiosa e più breve:
fn more_difficult_league<'a>(s1: &'a Stats, s2: &'a Stats) -> &'a str {
if s1.league == s2.league {
s1.league
} else {
s2.league
}
}
Se aggiungiamo un 'staticvalore di ritorno, la durata del caso peggiore è max('a, 'static)che presumibilmente è 'static:
fn more_difficult_league<'a>(s1: &'a Stats, s2: &'a Stats) -> &'static str {
if s1.league == s2.league {
s1.league
} else if s1.league == "PHP" {
s2.league
} else {
"C++"
}
}
Questo dà error[E0621]: explicit lifetime required in the type of s1e lifetime 'static requiredper s2.league.
A che punto la mia comprensione è sbagliata? Grazie in anticipo per avermi sopportato.
Disclaimer: help: add explicit lifetime 'static to the type of s1: &'a Stats<'static> funzionerebbe qui, ma mi sembra sbagliato.
Risposte
Modificherei il tuo codice come fornito di seguito.
Invece di fingere che il risultato di more_difficult_league()abbia una durata statica (che non è il caso quando ci riferiamo a s1o s2, e il compilatore se ne lamenta), possiamo introdurre una nuova annotazione della durata per questo risultato e specificare che la durata dei parametri deve sopravvivere a questo risultato (la whereclausola).
#[derive(Debug)]
struct Stats<'a> {
league: &'a str,
}
const NAME: &str = "rust";
fn more_difficult_league<'a, 'b, 'c>(
s1: &'a Stats,
s2: &'b Stats,
) -> &'c str
where
'a: 'c,
'b: 'c,
{
if s1.league == s2.league {
s1.league
} else if s1.league == "PHP" {
s2.league
} else {
"C++"
}
}
fn main() {
let st = Stats { league: NAME };
let dleague = more_difficult_league(&st, &st);
println!("{}", dleague);
}