Először nevezd meg, mire van szükséged

Ha a Rust fordítója megállít, könnyű minden függvényhívás elé egy clone()-t írni. Ezzel néhány hiba valóban eltűnik, de az adat életútja homályos marad. Tegyél fel inkább három kérdést: a fogadó kódnak saját példány kell, csak olvasnia kell, vagy módosítania kell az eredetit? A válasz a függvény aláírásában is megjelenhet.

Az alábbi példák egy névjegyzékből indulnak ki. A szöveg a hívóé; az ellenőrző függvénynek nincs oka elvenni vagy megtartani. A fogalmak hátterét az ownership és move leckében, a referenciákat a kölcsönzés leckében találod. Itt a konkrét hibajavításra koncentrálunk.

E0382: átadtad a tulajdont, majd újra használnád

A következő program szándékosan hibás. A kiir egy String értéket vesz át. A hívás után a nev változót mégis újra kiírnánk. Ezt jelzi az E0382 hiba magyarázata.

fn kiir(nev: String) { println!("{nev}"); }
fn main() {
    let nev = String::from("Réka");
    kiir(nev);
    println!("{nev}");
}

Ha csak olvasásra van szükség, a függvény kérjen &str értéket. A hívó kölcsönadja a szöveget, a hívás után pedig tovább használhatja. Ez az első javítás. A második lehetőség a tulajdon szándékos átadása: akkor a későbbi használatot kell megszüntetni vagy a függvényből visszaadni az értéket. A harmadik az önálló másolat, ha a két példány valóban külön életet él. Stringnél a klónozás ekkor indokolt lehet, de a szükségletet érdemes előbb megnevezni.

fn kiir(nev: &str) { println!("{nev}"); }
fn main() {
    let nev = String::from("Réka");
    kiir(&nev);
    assert_eq!(nev, "Réka");
}

E0502: ugyanazt az adatot olvasnád és módosítanád

Más helyzet, amikor nincs tulajdonosváltás, de egy élő referencia ütközik a módosítással. A következő programban az első elemre mutató referenciát a vektor bővítése után még használjuk. A bővítés megváltoztathatja a tárolást, ezért ez a két hozzáférés nem fér össze. Az E0502 leírása a kölcsönzések ütközését részletezi.

fn main() {
    let mut nevek = vec![String::from("Réka")];
    let elso = &nevek[0];
    nevek.push(String::from("Áron"));
    println!("{elso}");
}

Az első javítás a műveletek sorrendje: használd el a referenciát, és csak utána módosíts. A második lehetőség, hogy az elem adata helyett egy olcsón másolható eredményt tartasz meg, például a hosszát. A harmadik, ha tényleg a korábbi szöveg önálló pillanatképe kell, egy tudatos klón. Ezek nem felcserélhető trükkök: eltérő jelentésük van, amit a program céljához kell választani.

fn main() {
    let mut nevek = vec![String::from("Réka")];
    let elso = &nevek[0];
    assert_eq!(elso, "Réka");
    nevek.push(String::from("Áron"));
    assert_eq!(nevek.len(), 2);
}

Javítási rutin, amely nagyobb programban is segít

Olvasd el a hibaüzenetben megjelölt első kölcsönzést és az utolsó használatot. Ne csak a pirosan jelzett sort nézd. Rajzold fel, melyik függvénynek kell saját adat, és melyiknek elég referencia. Ha egy mező hosszú ideig kölcsönzött, gyakran jobb kisebb lépésekre bontani a feldolgozást, mint mindent megosztott módosítható állapotba csomagolni.

A példák Rust 1.97.1, edition 2024 környezetre készültek. A kísérő ellenőrző a hibás blokkoknál az elvárt hibakódot, a jó blokkoknál a sikeres fordítást és futást vizsgálja. A referenciák hivatalos fejezete ad további példákat; a következő saját gyakorlatodban cseréld ki a neveket egy valódi doménadatra, és indokold meg minden klón szükségességét.

ℹ
Megjegyzés

AI-val segített szerkesztőségi anyag. A technikai ellenőrzés környezetét a cikk végén jelezzük; emberi szakmai lektorálást ez a megjelölés nem állít.