Qachonki biza “let” orqali o’zgaruvchini e’lon qiladigan bo’lsak, unga berilgan qiymatni o’zgartira olmaymiz.
Misol uchun quyidagi kod ishlamaydi:
fn main() {
let my_number = 8;
my_number = 10; // ⚠️
}
Kompilyator “error[E0384]: cannot assign twice to immutable variable my_number” xatoligini ko’rsatadi. Sababi o’zgaruvchilarni faqatgina “let” bilan e’lon qilganda ularni qiymatini o’zgartirib bo’lmaydi.
Lekin ba’zida biz o’zgaruvchimizning qiymatini o’zgartirmoqchi bo’lamiz. Aynan shunday holatlar uchun “let” kalit so’zidan keyin “mut” ham qo’shib yozilishi kerak:
fn main() {
let mut my_number = 8;
my_number = 10;
}
Ana endi hech qanday xatolik chiqarilmaydi.
Lekin biz o’zgaruvchining ma’lumot turini o’zgartira olmmaymiz , xattoki “mut” yozilgan bo’lsa ham.
Quyidagi kod ham xatolik beradi:
fn main() {
let mut my_variable = 8; // bu o'zgaruvchining ma'lumot turi i32 va uni o'zgartirib bo'lmaydi
my_variable = "Hello, world!"; // ⚠️
}
Kompilyatordan esa har doimgidek ma’lumot turlarining boshqa-boshqaligi to’g’risida xatolik beradi: expected integer, found &str. Bu yerda &str asosan tekstlar uchun ishlatilinadigan “string” hisoblanadi.
Shadowing(soya qilish)
Umuman olganda “shadowing” terminining o’zbekcha ma’nosi “soya qilish” bo’lsa ham, keling biz uni “yashirish” deb nomlaymiz va nimaga unaqa ekanligini hozir bilib olasiz.
“Yashirish” bu “let” kalit so’zi orqali oldingi e’lon qilgan o’zgaruvchimizning nomi bilan yana huddi shunaqa o’zgaruvchi yaratish, lekin bu safar boshqa ma’lumot turini biriktirgan holda yaratsak ham bo’ladi. Boshida bu “o’zgaruvchanlik” ga o’xshashi mumkin, sababi o’zgaruvchining qiymati o’zgarayapti, ammo bu butunlay boshqacha. “Yashirish” ga misol qilib quyidagi kodni keltiramiz:
fn main() {
let my_number = 8; // Bu i32
println!("{}", my_number); // 8 chop etiladi
let my_number = 9.2; // Bu esa f64 lekin huddi o'sha nom bilan. Lekin bu birinchi my_number emas - Umuman boshqa turdagi ma'lumot turidir.
println!("{}", my_number) // 9.2 chop etadi.
}
Aynan shu holat uchun biz eski o’zgaruvchini “let” orqali yangi o’zgaruvchi orqasiga “yashirdik” deya olamiz
Unda birinchi o’zgaruvchi tugatildimi deyilgan savolga esa, Yo’q deb javob beramiz. Lekin endi “my_number” ni chaqiradigan bo’lsak “f64” ma’luumt turini olamiz. Oldingi va yangi o’zgaruvchi ham bitta blok “{}” ni ichida bo’lganini hisobiga biz eski o’zgaruvchini endi ko’ra olmaymiz.
Lekin ular 2 ta turli bloklarda bo’lsa, biz ulardan quyida usulda foydalana olamiz:
fn main() {
let my_number = 8; // Bu i32
println!("{}", my_number); // 8 chop etadi
{
let my_number = 9.2; // Bu esa f64. Bu tepadagi my_number emas - butunlay boshqa
println!("{}", my_number) // 9.2 chop etadi
// Lekin "yashirilgan" my_number faqat shu qatorgacha yashaydi
// shu qatordagi blok tugashi bilan birinchi my_number yana ishlaydi
}
println!("{}", my_number); // 8 chop etadi.
}
Shunda biz xulosa qilishimiz mumkinki, qachonki biz o’zgaruvchini “yashirsak” biz uni o’chirib tashlamaymiz, balki bloklab qo’yamiz.
Unda “yashirish” ning nima foydasi bor deb o’ylarsiz ? “Yashirish” asosan biz o’zgaruvchilarni tez-tez o’zgartirishimiz kerak bo’lgan vaqtda juda as qotadi. Tasavvur qiling, siz o’zgaruvchi bilan matematik amallar bajarmoqchisiz:
fn times_two(number: i32) -> i32 {
number * 2
}
fn main() {
let final_number = {
let y = 10;
let x = 9; // x 9 bilan boshlanadi
let x = times_two(x); // yangi x: 18 bilan yashiramiz
let x = x + y; // yana yangi x: 28 bilan yashiramiz
x // return x: final_number o'zgaruvchisining qiymati endi x ga teng
};
println!("The number is now: {}", final_number)
}
Agar “yashirish” uslubi bo’lmaganida, biz har bir matematik amal uchun alohida o’zgaruvchi nomi o’ylab topishimizga to’g’ri kelgan bo’lar edi.
fn times_two(number: i32) -> i32 {
number * 2
}
fn main() {
// Pretending we are using Rust without shadowing
let final_number = {
let y = 10;
let x = 9; // x 9 bilan boshlanadi
let x_twice = times_two(x); // x uchun ikkinchi nom
let x_twice_and_y = x_twice + y; // x uchun uchinchi nom!
x_twice_and_y // Agar "yashirish" usulini ishlatganimizda faqatgina x ni o'zi bilan yechsak ham bo'lardi...
};
println!("The number is now: {}", final_number)
}
Odatda Rust da “yashirish” usulini aynan shu ko’rinishda tasavvur qilamiz. Asosan, biror bir o’zgaruvchi bilan tezda qandaydir amal bajarib uni keyinchalik o’zgartirib yubormoqchi bo’lgan yokida uncha muhim bo’lmagan o’zgaruvchilar uchun qo’llaniladi.
Leave a Reply