Rust
Lifetimes
Szukaj…
Składnia
- funkcja fn <'a> (x: i' a Type)
- struct Struct <'a> {x: &' a Type}
- enum Enum <'a> {Variant (&' a Type)}
- impl <'a> Struct <' a> {fn x <'a> (& self) -> &' a Type {self.x}}
- impl <'a> Trait <' a> dla Type
- impl <'a> Cecha dla typu <' a>
-
fn function<F>(f: F) where for<'a> F: FnOnce(&'a Type)
-
struct Struct<F> where for<'a> F: FnOnce(&'a Type) { x: F }
-
enum Enum<F> where for<'a> F: FnOnce(&'a Type) { Variant(F) }
-
impl<F> Struct<F> where for<'a> F: FnOnce(&'a Type) { fn x(&self) -> &F { &self.x } }
Uwagi
- Wszystkie referencje w Rust mają swoją żywotność, nawet jeśli nie są wyraźnie opatrzone adnotacjami. Kompilator może domyślnie przypisywać czasy życia.
-
'static
czas życia jest przypisany do referencji, które są przechowywane w pliku binarnym programu i będą ważne przez cały czas jego wykonywania. Ten czas życia jest w szczególności przypisany literałom ciągów, które mają typ&'static str
ciąg&'static str
.
Parametry funkcji (czasy życia danych wejściowych)
fn foo<'a>(x: &'a u32) {
// ...
}
Określa to, że foo
ma czas życia 'a
, a parametr x
musi mieć czas życia co najmniej 'a
. Okresy istnienia funkcji są zwykle pomijane podczas wyboru dożywotniego okresu :
fn foo(x: &u32) {
// ...
}
W przypadku, gdy funkcja przyjmuje wiele referencji jako parametry i zwraca referencję, kompilator nie może wnioskować o czasie życia wyniku na podstawie elekcji życia .
error[E0106]: missing lifetime specifier
1 | fn foo(bar: &str, baz: &str) -> &i32 {
| ^ expected lifetime parameter
Zamiast tego należy wyraźnie określić parametry czasu życia.
// Return value of `foo` is valid as long as `bar` and `baz` are alive.
fn foo<'a>(bar: &'a str, baz: &'a str) -> &'a i32 {
Funkcje mogą również przyjmować wiele parametrów życia.
// Return value is valid for the scope of `bar`
fn foo<'a, 'b>(bar: &'a str, baz: &'b str) -> &'a i32 {
Pola konstrukcyjne
struct Struct<'a> {
x: &'a u32,
}
Oznacza to, że każde wystąpienie Struct
ma okres istnienia 'a
, a &u32
przechowywane w x
muszą mieć okres istnienia co najmniej 'a
.
Bloki Impl
impl<'a> Type<'a> {
fn my_function(&self) -> &'a u32 {
self.x
}
}
To określa, że Type
ma dożywotni okres 'a
i że odwołanie zwrócone przez my_function()
może już nie być poprawne po 'a
ponieważ Type
już nie istnieje, aby przechowywać self.x
Granice cechy wyższej rangi
fn copy_if<F>(slice: &[i32], pred: F) -> Vec<i32>
where for<'a> F: Fn(&'a i32) -> bool
{
let mut result = vec![];
for &element in slice {
if pred(&element) {
result.push(element);
}
}
result
}
Oznacza to, że odwołanie na i32 w granicy cechy Fn
może mieć dowolny okres istnienia.
Następujące nie działa:
fn wrong_copy_if<'a, F>(slice: &[i32], pred: F) -> Vec<i32>
where F: Fn(&'a i32) -> bool
{ // <----------------+
let mut result = vec![]; // 'a scope |
for &element in slice { // <--------+ |
if pred(&element) { // | |
result.push(element); // element's| |
} // scope | |
} // <--------+ |
result // |
} // <----------------+
Kompilator podaje następujący błąd:
error: `element` does not live long enough
if pred(&element) { // | |
^~~~~~~
ponieważ zmienna lokalna element
nie żyje tak długo jak 'a
całe życie” (jak widać z komentarzy kodu).
Życia nie można zadeklarować na poziomie funkcji, ponieważ potrzebujemy innego życia. Dlatego użyliśmy for<'a>
: do określenia, że referencja może być ważna dla dowolnego okresu istnienia (stąd można zastosować krótszy okres istnienia).
Granice cechy wyższej rangi można również stosować na strukturach:
struct Window<F>
where for<'a> F: FnOnce(&'a Window<F>)
{
on_close: F,
}
jak również na innych przedmiotach.
Granice cechy wyższej rangi są najczęściej używane z cechami Fn*
.
W przypadku tych przykładów eletime lifiction działa dobrze, więc nie musimy określać okresów istnienia.