- Sahibliyin üç qaydasını söyləmək və move ilə surət çıxarmanın fərqini izah etmək
&və&mutistinadları ilə qiyməti sahibliyi götürmədən funksiyaya vermək- E0382, E0499 və E0502 xətalarını oxumaq və düzəltmək
- Dilimlərlə işləmək və
Stringilə&strarasında düzgün seçim etmək
Sənin bir kitabın var. Onu dostuna bağışlaya bilərsən — onda kitab artıq sənin deyil. Onu bir neçə dosta eyni anda oxumağa verə bilərsən. Ya da onu yalnız bir dosta qeyd yazmağa verə bilərsən — o yazarkən başqa heç kim kitabı oxumamalıdır ki, yarımçıq qeydləri görməsin. Rust yaddaşı məhz bu məntiqlə idarə edir: sahiblik, oxumaq üçün borc və dəyişmək üçün borc.
Stek, heap və sahiblik qaydaları
Ölçüsü əvvəlcədən məlum olan qiymətlər (i32, bool, char) sürətli stekdə saxlanılır. Ölçüsü dəyişə bilən məlumat, məsələn, böyüyən mətn String, heap adlanan dinamik yaddaşda yerləşir: stekdə yalnız göstərici, uzunluq və tutum qalır. Heap-dəki yaddaşı kimsə azad etməlidir — Rust-da bu, sahibin işidir.
- Rust-da hər qiymətin bir sahibi var — onu saxlayan dəyişən.
- Eyni anda yalnız bir sahib ola bilər.
- Sahib görünmə sahəsindən (
{ }blokundan) çıxanda qiymət avtomatik silinir (drop) və yaddaş azad olunur.
Ötürmə (move), klonlama və Copy
let s2 = s1; yazanda String-in heap-dəki məzmunu kopyalanmır — sahiblik s1-dən s2-yə ötürülür (move). Əgər hər ikisi sahib olsaydı, blok bitəndə eyni yaddaşı iki dəfə azad edərdilər. Buna görə Rust s1-i etibarsız sayır və ondan istifadəni qadağan edir. Həqiqətən ikinci surət lazımdırsa, .clone() çağır.
fn main() {
let s1 = String::from("Baku");
let s2 = s1;
println!("{s1} {s2}");
}fn main() {
let s1 = String::from("Baku");
let s2 = s1.clone();
println!("{s1} {s2}");
}Baku Baku çap edir. clone heap-dəki məlumatın tam surətini yaradır, ona görə böyük məlumatda baha başa gəlir.error[E0382]: borrow of moved value: `s1`
--> src/main.rs:4:15
|
2 | let s1 = String::from("Baku");
| -- move occurs because `s1` has type `String`, which does not implement the `Copy` trait
3 | let s2 = s1;
| -- value moved here
4 | println!("{s1} {s2}");
| ^^^^ value borrowed here after moveTam ədədlər, kəsr ədədlər, bool, char və yalnız onlardan ibarət kortejlər Copy tiplərdir: onlar bütövlüklə stekdə yaşayır və surət çıxarmaq ucuzdur. Belə qiymətlər ötürülmür, surəti çıxarılır — let b = a;-dan sonra hər iki dəyişən işləkdir. Funksiyaya arqument vermək də eyni qaydaya tabedir:
fn take(text: String) {
println!("took: {text}");
}
fn show(n: i32) {
println!("copied: {n}");
}
fn main() {
let city = String::from("Ganja");
take(city);
// println!("{city}"); // error E0382: city was moved
let year = 2024;
show(year);
println!("still have: {year}");
}took: Ganja copied: 2024 still have: 2024
take String-in sahibi oldu və sonunda onu sildi. year isə i32 olduğu üçün sadəcə surəti ötürüldü.İstinadlar və borc götürmə
Hər dəfə sahibliyi verib geri almaq yorucudur. Bunun əvəzinə qiyməti borc vermək olar: &name sahibliyi götürməyən istinad yaradır. Funksiya istinadla qiyməti oxuyur, iş bitəndə isə sahib dəyişmir. Qiyməti dəyişmək üçün dəyişən istinad &mut lazımdır — bunun üçün dəyişənin özü də mut olmalıdır.
fn length(text: &String) -> usize {
text.len()
}
fn add_suffix(text: &mut String) {
text.push_str(" city");
}
fn main() {
let mut name = String::from("Baku");
let len = length(&name);
println!("{name} has {len} letters");
add_suffix(&mut name);
println!("{name}");
}Baku has 4 letters Baku city
İstənilən anda qiymətə ya istənilən sayda & istinadı, ya da yalnız bir &mut istinadı ola bilər — ikisi birlikdə yox. İstinadlar isə həmişə etibarlı olmalıdır: istinad sahibindən uzun yaşaya bilməz. İstinad son dəfə istifadə olunduğu yerdə «bitir».
fn main() {
let mut s = String::from("hi");
let r1 = &mut s;
let r2 = &mut s;
r1.push('!');
r2.push('?');
println!("{s}");
}fn main() {
let mut s = String::from("hi");
let r1 = &mut s;
r1.push('!');
let r2 = &mut s;
r2.push('?');
println!("{s}");
}&mut eyni anda «canlıdır» (cannot borrow s as mutable more than once at a time). Sağda r1 son dəfə push-da istifadə olunur və r2 yaranandan əvvəl bitir.fn main() {
let mut scores = vec![90, 85];
let first = &scores[0];
scores.push(70);
println!("{first}");
}fn main() {
let mut scores = vec![90, 85];
let first = scores[0];
scores.push(70);
println!("{first}");
}vec![...] böyüyə bilən siyahı (Vec) yaradır. Sağda first istinad yox, i32 qiymətinin surətidir, ona görə siyahını dəyişmək olar.error[E0502]: cannot borrow `scores` as mutable because it is also borrowed as immutable
--> src/main.rs:4:5
|
3 | let first = &scores[0];
| ------ immutable borrow occurs here
4 | scores.push(70);
| ^^^^^^^^^^^^^^^ mutable borrow occurs here
5 | println!("{first}");
| ------- immutable borrow later used hereDilimlər: String və &str
Dilim (slice) kolleksiyanın bir hissəsinə istinaddır: &numbers[1..4] 1, 2 və 3 indeksli elementləri göstərir. Mətn dilimi &str tipindədir. Proqramdakı hər mətn literalı ("hello") da &str-dir: o, proqram faylının içindəki mətnə baxan istinaddır. String isə öz məlumatının sahibidir, heap-də yaşayır və böyüyə bilər.
fn first_word(text: &str) -> &str {
for (i, ch) in text.char_indices() {
if ch == ' ' {
return &text[..i];
}
}
text
}
fn main() {
let sentence = String::from("hello brave world");
let word = first_word(&sentence);
println!("{word}");
println!("{}", first_word("Rust"));
let numbers = [10, 20, 30, 40, 50];
let middle = &numbers[1..4];
println!("{:?} len={}", middle, middle.len());
}hello Rust [20, 30, 40] len=3
first_word həm &String, həm də literal qəbul edir: Rust &String-i avtomatik &str-ə çevirir. &text[..i] əvvəldən i baytına qədər olan hissədir.| Xüsusiyyət | String | &str |
|---|---|---|
| Sahiblik | məlumatın sahibidir | borc götürür |
| Dəyişmək | mut ilə böyüyə bilər: push_str | yalnız oxumaq |
| Yaratmaq | String::from("hi"), "hi".to_string() | "hi", &s, &s[0..2] |
| Tipik yeri | struktur sahələri, mətn qurmaq | funksiya parametrləri |
Əsas fikirlər
- Hər qiymətin bir sahibi var; sahib görünmə sahəsindən çıxanda qiymət silinir.
Stringkimi tiplər mənimsədiləndə və funksiyaya veriləndə ötürülür (move); Copy tiplərin isə surəti çıxarılır.&oxumaq üçün,&mutdəyişmək üçün borc götürür; sahiblik dəyişmir.- Eyni anda ya çoxlu
&, ya da tək&mutola bilər; istinad sahibindən uzun yaşamır. &strmətn dilimidir,Stringisə öz məlumatına sahib olan, böyüyə bilən mətndir; parametrlərdə&stryaz.
Özünü yoxla
10 sual. Hər düzgün cavab XP qazandırır.
let a = String::from("x"); let b = a; kodundan sonra hansı dəyişəndən istifadə etmək olar?