2015-09-21 14 views
5

Mam HashMap, który używa char dla klucza i struct dla wartości.Jak mogę powrócić nową struct z Opcji :: unwrap_or?

get() metoda HashMap będzie często być wywołana z kluczy, które nie są w HashMap, więc chciałbym użyć unwrap_or() na zwróconej opcja tworzenia domyślnego struct wartość. Jednak, gdy próbuję to zrobić, kompilator wyrzuca następujący błąd (z temp jest wartość domyślna, że ​​jestem stara się powrócić):

lib.rs:51:4: 51:8 error: `temp` does not live long enough 

Oto mały reproducer:

struct Sample { 
    thing: i32 
} 

fn do_stuff() { 
    let map = HashMap::<char, Sample>::new(); 

    let sample = map.get(&'a').unwrap_or({ 
     let temp = Sample { 
      thing : 0 
     }; 
     &temp 
    }); 
} 

mam dwa pytania:

  1. Czy istnieje sposób, aby temp wiążące żyją dłużej?
  2. Czy istnieje lepszy sposób, aby nie spaść z powrotem na domyślny struct przypadku korzystania z opcji?

Odpowiedz

4

Dla precyzyjnego scenariusza, można zrobić coś takiego:

use std::collections::HashMap; 
struct Sample { 
    thing : i32 
} 

fn main() { 
    let map = HashMap::<char, Sample>::new(); 
    let temp = Sample { thing : 0 }; 
    let sample = map.get(&'a').unwrap_or(&temp); 
} 

Często jednak chcesz coś bardziej jak to:

use std::collections::HashMap; 
#[derive(Clone)] 
struct Sample { 
    thing : i32 
} 

fn get_sample(map: &HashMap<char, Sample>) -> Sample 
{ 
    map.get(&'a').cloned().unwrap_or_else(|| { 
     Sample { thing : 0 } 
    }) 
} 

Jeśli naprawdę chcesz warunkowo zainicjować i wziąć adres zmiennej lokalnej, to jest możliwe, ale nie mogą być pisane unwrap_or lub unwrap_or_else:

use std::collections::HashMap; 
struct Sample { 
    thing : i32 
} 

fn main() { 
    let map = HashMap::<char, Sample>::new(); 
    let temp; 
    let sample = match map.get(&'a') { 
     Some(sample) => sample, 
     None => { 
      temp = Sample { thing : 0 }; 
      &temp 
     } 
    }; 
} 
+0

Jakoś przeoczyłem, że możesz przesłać dalej, deklarując powiązanie, jak to jest zrobione w punkcie 3. Nie sądzę, że widziałem jakiekolwiek użycie deklaracji do przodu w książce Rust lub gdziekolwiek indziej. Dzięki! –

2

pamiętać, że kwestia pokazuje masz nieporozumień root:

Jak mogę powrócić nowej struktury

Ale wtedy Twój kod mówi tak:

&temp 

To odniesienie do struktury. Problemem jest to, że struktura żyje tylko na czas trwania bloku przekazany jako argument do unwrap_or. Zaraz po zakończeniu bloku wszystkie zmienne, które nie są zwracane z bloku, są pomijane, unieważniając wszelkie odniesienia do nich.

Czy istnieje sposób na wydłużenie czasu wiązania tymczasowego?

Istnieje jeden sposób, aby powiązanie trwało dłużej: przenieś tam, gdzie jest kod. Jeśli wcześniej przeniesiesz tworzenie zmiennej, jej żywotność rozpocznie się wcześniej. Dlatego działa Eli Friedman's first solution.

Jeśli zmienisz kod, aby zwrócić struct, a nie odwołanie, to wyjaśnia, jak działa drugie rozwiązanie i lepiej pasuje do sposobu modelowania problemu. Nie zawsze możesz jednak przejść od odniesienia do nie-odniesienia, a czasami nawet nie jest to możliwe.