2015-04-03 11 views
29

Istnieje kilka pytań, które wydają się dotyczyć tego samego problemu, który mam. Na przykład zobacz here i here. Zasadniczo próbuję zbudować String w funkcji lokalnej, ale następnie zwrócić go jako &str. Krojenie nie działa, ponieważ czas życia jest za krótki. Nie mogę użyć str bezpośrednio w funkcji, ponieważ muszę ją budować dynamicznie. Wolałbym jednak nie zwracać wartości String, ponieważ natura obiektu, do którego przechodzi, jest statyczna po jej zbudowaniu. Czy istnieje sposób na zjedzenie mojego ciasta i zjedzenie go?Zwróć ciąg lokalny jako plaster (& str)

Oto minimalne zakaz sporządzania reprodukcji:

fn return_str<'a>() -> &'a str { 
    let mut string = "".to_string(); 

    for i in 0..10 { 
     string.push_str("ACTG"); 
    } 

    &string[..] 
} 
+3

Inne pytania mają ten sam problem, a odpowiedź jest nadal samo: nie jest możliwe zbudowanie 'String' w funkcji i zwrócenie go jako' & str' z powodu modelu pamięci Rust. – Levans

+1

Twoje rozumowanie, że nie chcesz zwrócić "Stringa", nie ma dla mnie sensu. Wystarczy zapisać 'String' w tym" statycznym "obiekcie zamiast' i str'. Jest to łatwiejsze, przynajmniej tak samo ergonomiczne, że ma więcej sensu pod względem własności i nie ma żadnej przewagi wydajności. – delnan

+0

@delnan Właściwie odpowiedziałeś na coś innego, o co się zastanawiałem, a to, czy użycie '' String'' ma jakieś wady wydajnościowe. Powinienem móc refaktor używać '' String''s – anderspitman

Odpowiedz

47

Nie, nie mogę tego zrobić. Istnieją przynajmniej dwa wyjaśnienia, dlaczego tak się dzieje.

Po pierwsze, pamiętaj, że referencje są pożyczane, tzn. Wskazują pewne dane, ale nie są ich właścicielami, są własnością kogoś innego. W tym konkretnym przypadku ciąg, kawałek, do którego chcesz zwrócić, jest własnością tej funkcji, ponieważ jest przechowywany w zmiennej lokalnej.

Po zakończeniu funkcji wszystkie jej zmienne lokalne zostają zniszczone; obejmuje to wywoływanie destruktorów, a destruktor z String zwalnia pamięć używaną przez ciąg. Jednak chcesz zwrócić pożyczone odniesienie wskazujące dane przydzielone dla tego ciągu. Oznacza to, że zwrócony odnośnik natychmiast zwisa - wskazuje na niepoprawną pamięć!

Rust został stworzony pośród wszystkich innych elementów, aby zapobiec takim problemom. Dlatego w Rust nie można zwrócić odniesienia wskazującego na lokalne zmienne funkcji, co jest możliwe w językach takich jak C.

Istnieje również inne wyjaśnienie, nieco bardziej formalne. Spójrzmy na podpisie funkcji:

fn return_str<'a>() -> &'a str 

Pamiętaj, że trwałość i parametry generyczne są, dobrze, parametry: są one ustawione przez wywołującego funkcję. Na przykład, jakaś inna funkcja może nazwać tak:

let s: &'static str = return_str(); 

Wymaga to 'a być 'static, ale jest to oczywiście niemożliwe - czynność nie zwraca odwołanie do pamięci statycznej, to zwraca odwołanie z o znacznie mniejszym życiu. Tak więc taka definicja funkcji jest wadliwa i jest zabroniona przez kompilator.

Zresztą w takich sytuacjach trzeba zwrócić wartość z posiadanego typu, w tym konkretnym przypadku będzie to własność String:

fn return_str() -> String { 
    let mut string = String::new(); 

    for _ in 0..10 { 
     string.push_str("ACTG"); 
    } 

    string 
} 
+2

Technicznie możesz zwrócić 'String' jako' 'static', o ile wyciekniesz 'String'. (Z 'std :: mem :: forget'), Ale pozostanie przydzielone na zawsze. (Które domyślam się, że chodzi o "statyczne") –

Powiązane problemy