Reference lar funksiyalar uchun juda ham foydali hisoblanadi. Sababi, Rust dagi asosiy qonunlardan biri shuki: har qanday qiymat faqatgina bitta o’zgaruvchiga tegishli bo’lishi kerak.
Misol uchun quyidagi blokdagi kod ishlamaydi:
fn print_country(country_name: String) {
println!("{}", country_name);
}
fn main() {
let country = String::from("Austria");
print_country(country); // "Austria" chop etiladi
print_country(country); // ⚠️ Yana bir martta chop etib ko'ramiz
}
Bu blokning ishlamasligini asosiy sababi shuki, “country” o’zgaruvchisi birinchi martta funksiyaga berganimizdayoq uning umri tugagan.
- Qadam 1: “country” nomi ostida “String” ma’lumot turidagi o’zgaruvchi yaratamiz.
- Qadam 2: Biz “country” ni “print_country” funksiyasiga beramiz. “print_country” da ko’rib turganimizdek, hech qanday qaytuvchi qiymat yo’q. Shuning uchun ham “print_country” tugaganidan so’ng, bizning “String” ning umri tugaydi.
- Qadam 3: Agar biz yana “country” ni , “print_country” ga bermoqchi bo’lsak, bizga xatolik chiqadi sababi “country” da qiymat qolmagan.
“print_country” funksiyasiga ozgina o’zgartirish kiritib bizga “String” qaytaradigan qilishimiz mumkin.
fn print_country(country_name: String) -> String {
println!("{}", country_name);
country_name // bu yerda qiymat qaytariladi
}
fn main() {
let country = String::from("Austria");
let country = print_country(country); // o'zgaruvchini qayta e'lon qilib qiymatini saqlab olamiz
print_country(country);
}
Endi esa quyidagi qiymat kelib chiqadi:
Austria
Austria
Tepadagi xatolikni yana ham optimalroq yo’l bilan ham to’g’rilasak bo’ladi:
fn print_country(country_name: &String) {
println!("{}", country_name);
}
fn main() {
let country = String::from("Austria");
print_country(&country); // "Austria" chop etiladi
print_country(&country); // Huddi shu harakatni yana qaytaramiz
}
Endi, “print_country()” funksiyasi bizdagi “String” qiymatga faqatgina reference ola oladi. Sababi biz funksiyaga &country orqali beramiz.
Huddi shu funksiyani o’zgaruvchi reference bilan ham ifodalab ko’ramiz:
fn add_hungary(country_name: &mut String) { // funksiyamiz o'zgaruvchi reference oladi
country_name.push_str("-Hungary"); // push_str() String ga &str qo'shadi
println!("Now it says: {}", country_name);
}
fn main() {
let mut country = String::from("Austria");
add_hungary(&mut country); // funksiyaga ham o'zgaruvchi reference berishimiz kerak.
}
Oxirgi natija esa:
Now it says: Austria-Hungary
Tepadagi misollardan kelib chiqib xulosa qiladigan bo’lsak:
n function_name(variable: String)funksiya “String” qiymat oladi va egalik oladi, agar funksiya hech qanday qiymat qaytarmasa, berilgan o’zgaruvchi funksiya tugashi bilan umri tugaydi.fn function_name(variable: &String)“String” ga reference oladi va o’qiy oladifn function_name(variable: &mut String)“String” ga reference oladi va o’zgartira oladi
Quyidagi misolda ham o’zgaruvchan reference deb ko’rinishi mumkin, lekin aslida bunday emas:
fn main() {
let country = String::from("Austria"); // "country" o'zgaruvchan reference emas lekin Austria-Hungary chop etamiz
adds_hungary(country);
}
fn adds_hungary(mut country: String) { // Bu yerda adds_hungary funksiya "String" oladi va uni keyin o'zgaruvchi reference qilib e'lon qiladi.
country.push_str("-Hungary");
println!("{}", country);
}
Bu qanday amalga oshishi mumkin ? Sababi “mut country” reference emas, shuning uchun ham “adds_hungary” ga berganimizda uni o’zlashtirib oladi. “adds_hungary” ni chaqirishimiz bilan, unga berilgan qiymatning to’liq egasiga aylanadi. Shundan so’ng “country” o’zgaruvchisining String::from("Austria") bilan umuman bog’liqlik joyi qolmaydi va “adds_hungary” funksiyamiz qiymatni hoxlagancha o’zgartirishi mumkin va bu xavfsiz hisoblanadi.
Leave a Reply