To nie wydaje się możliwe ani pożądane. 'staticżywotność oznaczałaby, że ciąg nigdy nie zostałby cofnięty, tj. wyciek pamięci. Dlaczego potrzebujesz &'static strzamiast &'a strjakiegoś odpowiedniego 'a?
3
Jak by to wyglądało, gdyby to przekształcić w &'a str to?
Christoph
Via as_slice. Byłoby łatwiej, gdybyś opisał, jaki konkretny problem próbujesz rozwiązać i jakie problemy napotykasz przy tym.
Zwróć również uwagę SendStrna typ, który jest ciągiem będącym własnością lub ciągiem statycznym.
Chris Morgan
Odpowiedzi:
135
Zaktualizowano dla Rust 1.0
Nie możesz uzyskać &'static strod a, Stringponieważ Strings mogą nie żyć przez całe życie twojego programu i to właśnie &'staticoznacza życie. Możesz uzyskać z niego tylko wycinek sparametryzowany przez Stringwłasny okres istnienia.
Aby przejść od a Stringdo plasterka &'a str, możesz użyć składni krojenia:
let s: String = "abcdefg".to_owned();
let s_slice: &str = &s[..]; // take a full slice of the string
let s_slice: &str = &*s; // s : String // *s : str (via Deref<Target=str>)// &*s: &str
Istnieje nawet inny sposób, który pozwala na jeszcze bardziej zwięzłą składnię, ale można go użyć tylko wtedy, gdy kompilator jest w stanie określić żądany typ docelowy (np. W argumentach funkcji lub jawnie wpisanych wiązaniach zmiennych). Nazywa się to deref coercion i pozwala na użycie tylko &operatora, a kompilator automatycznie wstawi odpowiednią ilość *s na podstawie kontekstu:
let s_slice: &str = &s; // okayfntake_name(name: &str) { ... }
take_name(&s); // okay as welllet not_correct = &s; // this will give &String, not &str,// because the compiler does not know// that you want a &str
Zauważ, że ten wzorzec nie jest unikalny dla String/ &str- możesz go użyć z każdą parą typów, które są połączone Deref, na przykład z CString/ CStri OsString/ OsStrz std::ffimodułu lub PathBuf/ Pathz std::pathmodułu.
W Rust 1.10 zamiast tego let s_slice: &str = &s[..];możesz po prostu zrobić to:let s_slice: &str = s.as_str();
Shnatsel
3
Czasami oryginalny ciąg nie jest wystarczająco żywy, jak w bloku dopasowania {...}. Doprowadzi to do 's' does not live long enough error.
Dereckson
41
Możesz to zrobić, ale wiąże się to z wyciekiem pamięciString . Nie należy tego robić lekko. Wyciekając z pamięci String, gwarantujemy, że pamięć ta nigdy nie zostanie uwolniona (a tym samym wyciek). Dlatego wszelkie odwołania do obiektu wewnętrznego mogą być interpretowane jako mające 'staticokres istnienia.
Stringdaje gwarancję, że dopóki obiekt nie zostanie upuszczony, pamięć pozostaje żywa. Ponieważ mem::forgetgwarantujemy, że obiekt nigdy nie zostanie porzucony, mamy gwarancję, że odwołanie do zawartego w nim strnigdy nie będzie nieprawidłowe. W ten sposób możemy stwierdzić, że jest to 'staticodniesienie
oli_obk
1
Było to niezwykle pomocne dla mojej aplikacji Rust, która musiała przekształcić a Stringw a &'static str, aby tokeny utworzone na podstawie oryginału Stringbyły dostępne we wszystkich wątkach. Bez tego kompilator Rust narzekałby, że moje Stringżycie kończyło się wraz z końcem głównej funkcji, co nie było wystarczająco dobre, ponieważ nie miało 'staticgwarancji.
mmstick
1
@mmstick: lepszym rozwiązaniem w takim przypadku byłoby użycie crossbeamwątków o określonym zakresie
oli_obk
3
@mmstick: jeśli umieścisz całą aplikację w zasięgu belki poprzecznej i utworzysz ciąg poza zasięgiem, otrzymasz dokładnie to.
oli_obk
1
Ta odpowiedź jest świetna! Powiedział mi, jak przebiegło stworzyć statyczny kawałek struny i przekonał mnie, żebym tego nie robił! Zdecydowałem się zreformować moją aplikację, aby nie używać statycznych wycinków ciągów w tak wielu miejscach.
Paul Chernoch,
23
Od wersji Rust 1.26 możliwe jest przekonwertowanie pliku Stringna &'static strbez użycia unsafekodu:
To przekształca Stringinstancję w pudełkową stri natychmiast ją przecieka. To uwalnia całą nadmiarową pojemność, jaką struna może obecnie zajmować.
Zauważ, że prawie zawsze istnieją rozwiązania, które są lepsze niż przeciekające obiekty, np. Użycie crossbeamskrzynki, jeśli chcesz podzielić stan między wątkami.
TL; DR: możesz dostać &'static strod, Stringktóry sam ma 'staticcałe życie.
Chociaż inne odpowiedzi są poprawne i najbardziej przydatne, istnieje (niezbyt przydatny) przypadek skrajny, w którym rzeczywiście można przekonwertować a Stringna &'static str:
Okres istnienia odwołania musi zawsze być krótszy lub równy okresowi istnienia obiektu, do którego się odwołuje. Oznacza to, że obiekt, do którego odwołuje się odwołanie, musi żyć dłużej (lub tak samo długo) niż odniesienie. Ponieważ 'staticoznacza cały czas trwania programu, dłuższe życie nie istnieje. Ale wystarczy równe życie. Więc jeśli Stringma żywotność 'static, możesz uzyskać&'static str z niego odniesienie.
Tworzenie statictypu Stringteoretycznie stało się możliwe w Rust 1.31, kiedy ta const fnfunkcja została wydana. Niestety jedyną funkcją const zwracającą a StringjestString::new() obecnie i nadal znajduje się za bramą funkcji (więc na razie wymagana jest nocna funkcja Rust).
Tak więc poniższy kod wykonuje żądaną konwersję (używając nightly) ... i tak naprawdę nie ma praktycznego zastosowania z wyjątkiem kompletnego pokazania, że jest to możliwe w tym przypadku skrajnym.
'static
żywotność oznaczałaby, że ciąg nigdy nie zostałby cofnięty, tj. wyciek pamięci. Dlaczego potrzebujesz&'static str
zamiast&'a str
jakiegoś odpowiedniego'a
?&'a str
to?as_slice
. Byłoby łatwiej, gdybyś opisał, jaki konkretny problem próbujesz rozwiązać i jakie problemy napotykasz przy tym.SendStr
na typ, który jest ciągiem będącym własnością lub ciągiem statycznym.Odpowiedzi:
Zaktualizowano dla Rust 1.0
Nie możesz uzyskać
&'static str
od a,String
ponieważString
s mogą nie żyć przez całe życie twojego programu i to właśnie&'static
oznacza życie. Możesz uzyskać z niego tylko wycinek sparametryzowany przezString
własny okres istnienia.Aby przejść od a
String
do plasterka&'a str
, możesz użyć składni krojenia:let s: String = "abcdefg".to_owned(); let s_slice: &str = &s[..]; // take a full slice of the string
Alternatywnie możesz użyć faktu, że
String
implementujeDeref<Target=str>
i przeprowadza jawne ponowne pożyczanie:let s_slice: &str = &*s; // s : String // *s : str (via Deref<Target=str>) // &*s: &str
Istnieje nawet inny sposób, który pozwala na jeszcze bardziej zwięzłą składnię, ale można go użyć tylko wtedy, gdy kompilator jest w stanie określić żądany typ docelowy (np. W argumentach funkcji lub jawnie wpisanych wiązaniach zmiennych). Nazywa się to deref coercion i pozwala na użycie tylko
&
operatora, a kompilator automatycznie wstawi odpowiednią ilość*
s na podstawie kontekstu:let s_slice: &str = &s; // okay fn take_name(name: &str) { ... } take_name(&s); // okay as well let not_correct = &s; // this will give &String, not &str, // because the compiler does not know // that you want a &str
Zauważ, że ten wzorzec nie jest unikalny dla
String
/&str
- możesz go użyć z każdą parą typów, które są połączoneDeref
, na przykład zCString
/CStr
iOsString
/OsStr
zstd::ffi
modułu lubPathBuf
/Path
zstd::path
modułu.źródło
let s_slice: &str = &s[..];
możesz po prostu zrobić to:let s_slice: &str = s.as_str();
's' does not live long enough error
.Możesz to zrobić, ale wiąże się to z wyciekiem pamięci
String
. Nie należy tego robić lekko. Wyciekając z pamięciString
, gwarantujemy, że pamięć ta nigdy nie zostanie uwolniona (a tym samym wyciek). Dlatego wszelkie odwołania do obiektu wewnętrznego mogą być interpretowane jako mające'static
okres istnienia.fn string_to_static_str(s: String) -> &'static str { Box::leak(s.into_boxed_str()) } fn main() { let mut s = String::new(); std::io::stdin().read_line(&mut s).unwrap(); let s: &'static str = string_to_static_str(s); }
źródło
String
daje gwarancję, że dopóki obiekt nie zostanie upuszczony, pamięć pozostaje żywa. Ponieważmem::forget
gwarantujemy, że obiekt nigdy nie zostanie porzucony, mamy gwarancję, że odwołanie do zawartego w nimstr
nigdy nie będzie nieprawidłowe. W ten sposób możemy stwierdzić, że jest to'static
odniesienieString
w a&'static str
, aby tokeny utworzone na podstawie oryginałuString
były dostępne we wszystkich wątkach. Bez tego kompilator Rust narzekałby, że mojeString
życie kończyło się wraz z końcem głównej funkcji, co nie było wystarczająco dobre, ponieważ nie miało'static
gwarancji.crossbeam
wątków o określonym zakresieOd wersji Rust 1.26 możliwe jest przekonwertowanie pliku
String
na&'static str
bez użyciaunsafe
kodu:fn string_to_static_str(s: String) -> &'static str { Box::leak(s.into_boxed_str()) }
To przekształca
String
instancję w pudełkowąstr
i natychmiast ją przecieka. To uwalnia całą nadmiarową pojemność, jaką struna może obecnie zajmować.Zauważ, że prawie zawsze istnieją rozwiązania, które są lepsze niż przeciekające obiekty, np. Użycie
crossbeam
skrzynki, jeśli chcesz podzielić stan między wątkami.źródło
TL; DR: możesz dostać
&'static str
od,String
który sam ma'static
całe życie.Chociaż inne odpowiedzi są poprawne i najbardziej przydatne, istnieje (niezbyt przydatny) przypadek skrajny, w którym rzeczywiście można przekonwertować a
String
na&'static str
:Okres istnienia odwołania musi zawsze być krótszy lub równy okresowi istnienia obiektu, do którego się odwołuje. Oznacza to, że obiekt, do którego odwołuje się odwołanie, musi żyć dłużej (lub tak samo długo) niż odniesienie. Ponieważ
'static
oznacza cały czas trwania programu, dłuższe życie nie istnieje. Ale wystarczy równe życie. Więc jeśliString
ma żywotność'static
, możesz uzyskać&'static str
z niego odniesienie.Tworzenie
static
typuString
teoretycznie stało się możliwe w Rust 1.31, kiedy taconst fn
funkcja została wydana. Niestety jedyną funkcją const zwracającą aString
jestString::new()
obecnie i nadal znajduje się za bramą funkcji (więc na razie wymagana jest nocna funkcja Rust).Tak więc poniższy kod wykonuje żądaną konwersję (używając nightly) ... i tak naprawdę nie ma praktycznego zastosowania z wyjątkiem kompletnego pokazania, że jest to możliwe w tym przypadku skrajnym.
#![feature(const_string_new)] static MY_STRING: String = String::new(); fn do_something(_: &'static str) { // ... } fn main() { do_something(&MY_STRING); }
źródło