Wymaga to higher rank trait bounds, w szczególności okresów wyższej rangi. Pełna nienazwana składnia byłaby F: for<'a> FnOnce<(&'a mut Builder,),()>
.
Użycie całego cyklu życia funkcji nie działa, np. gdybyśmy mieli
pub fn build<'b, F>(rules: F) -> Builder where F: FnOnce<(&'b mut Builder,),()>
Ten mówi, że build
współpracuje z każdym żywotność rozmówca chce (np mógł wybrali 'b
== 'static
), ale to nieważne, bo nie ma konkretnego beton życia, która musi być wykorzystana : żywotność &mut builder
wewnątrz funkcji. Używanie F: for<'a> ...
w oprawie mówi, że F
działa z dowolnym czasem życia 'a
, więc kompilator widzi, że można go zastąpić w wersji &mut builder
.
Jak wspomniałem powyżej, jest to naprawdę brzydka, nieumiejętna składnia. Są dwa kolejne sposoby, dzięki którym można zrobić o wiele ładniej. Po pierwsze, kanoniczny sposób używania cech zamknięcia to: ()
sugar: for<'a> FnOnce(&'a mut Builder) ->()
, lub podobnie jak z resztą rdzy, ->()
może zostać upuszczone: for<'a> FnOnce(&'a mut Builder)
. (. NB jest to cukier dla FnOnce<...>
, ale tylko składnia słodzone będą stabilizowane przez oddziaływania z tych cech w 1.0.)
Następnie składnia paren ma trochę więcej regułę: automatycznie wstawia wcieleń, które działają jak for<'a>
(konkretnie, podlega lifetime elision z każdym wprowadzonym czasem życia umieszczonym w for
na cechie), więc tylko F: FnOnce(&mut Builder)
jest równoważne F: for<'a> FnOnce(&'a mut Builder)
i jest to zalecana wersja.
Stosując te poprawki do kojec przykład:
pub fn initialize_with_closure<F>(rules: F) -> uint where F: FnOnce(&mut uint) {
let mut i = 0;
rules(&mut i);
i
}
// equivalently
pub fn initialize_with_closure_explicit<F>(rules: F) -> uint where F: for<'a> FnOnce(&'a mut uint) ->() {
let mut i = 0;
rules(&mut i);
i
}
pub fn main() {
initialize_with_closure(|i: &mut uint| *i = *i + 20);
initialize_with_closure_explicit(|i: &mut uint| *i = *i + 20);
}
playpen
Close-wyborca: dlaczego jest to offtopic? – huon