- Üç sahiplik kuralını söylemek ve taşıma ile kopyalama arasındaki farkı açıklamak
- Değerleri
&ve&mutreferanslarıyla sahipliği almadan fonksiyonlara vermek - E0382, E0499 ve E0502 hatalarını okumak ve düzeltmek
- Dilimlerle çalışmak ve
Stringile&strarasında doğru seçim yapmak
Bir kitabın var. Onu bir arkadaşına hediye edebilirsin; o zaman artık senin değildir. Aynı anda birkaç arkadaşına okumaları için ödünç verebilirsin. Ya da yalnızca bir arkadaşına not yazması için verebilirsin; o yazarken yarım kalmış notları görmesin diye başka kimse kitabı okumamalıdır. Rust belleği tam da bu mantıkla yönetir: sahiplik, okumak için ödünç ve değiştirmek için ödünç.
Yığın, öbek ve sahiplik kuralları
Boyutu önceden bilinen değerler (i32, bool, char) hızlı yığında (stack) tutulur. Boyutu değişebilen veriler, örneğin büyüyen bir String, öbek (heap) denen dinamik bellekte bulunur: yığında yalnızca bir işaretçi, uzunluk ve kapasite kalır. Öbekteki belleği birinin serbest bırakması gerekir; Rust'ta bu, sahibin işidir.
- Rust'ta her değerin bir sahibi vardır: onu tutan değişken.
- Aynı anda yalnızca bir sahip olabilir.
- Sahip kapsam dışına çıktığında (
{ }bloğu bittiğinde) değer otomatik olarak düşürülür (drop) ve belleği serbest bırakılır.
Taşıma, klonlama ve Copy
let s2 = s1; yazdığında String'in öbekteki içeriği kopyalanmaz; sahiplik s1'den s2'ye taşınır (move). İkisi de sahip olsaydı, blok bittiğinde aynı belleği iki kez serbest bırakırlardı. Bu yüzden Rust s1'i geçersiz sayar ve kullanılmasını yasaklar. Gerçekten ikinci bir kopya gerekiyorsa .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 yazdırır. clone, öbekteki verinin tam bir kopyasını oluşturur; bu yüzden büyük verilerde pahalıdır.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 sayılar, ondalıklı sayılar, bool, char ve yalnızca bunlardan oluşan demetler Copy türleridir: tamamen yığında yaşarlar ve kopyalanmaları ucuzdur. Bu tür değerler taşınmaz, kopyalanır; let b = a; sonrasında iki değişken de kullanılabilir. Bir fonksiyona argüman vermek de aynı kurala uyar:
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 ve sonunda onu düşürdü. year ise i32 olduğu için yalnızca kopyası verildi.Referanslar ve ödünç alma
Sahipliği her seferinde verip geri almak yorucudur. Bunun yerine değeri ödünç verebilirsin: &name, sahipliği almayan bir referans oluşturur. Fonksiyon değeri referans üzerinden okur, sonrasında sahip değişmez. Değeri değiştirmek için değiştirilebilir referans &mut gerekir; bunun için değişkenin kendisi de 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
Herhangi bir anda bir değerin ya istediği kadar & referansı ya da yalnızca bir &mut referansı olabilir; ikisi birlikte asla. Ayrıca referanslar her zaman geçerli olmalıdır: bir referans sahibinden uzun yaşayamaz. Bir referans, son kullanıldığı yerde “biter”.
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 referansı aynı anda “canlı” (cannot borrow s as mutable more than once at a time). Sağda r1 son kez push içinde kullanılır ve r2 oluşturulmadan önce biter.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üyebilen bir liste (Vec) oluşturur. Sağda first bir referans değil, i32 değerinin kopyasıdır; bu yüzden liste değiştirilebilir.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 hereDilimler: String ve &str
Dilim (slice), bir koleksiyonun bir kısmına referanstır: &numbers[1..4], 1, 2 ve 3 indeksli elemanları gösterir. Metin diliminin türü &str'dir. Programdaki her metin değişmezi ("hello") de bir &str'dir: program dosyasının içinde saklanan metne bakan bir referans. String ise kendi verisinin sahibidir, öbekte yaşar ve büyüyebilir.
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 hem &String hem de değişmez kabul eder: Rust, &String'i otomatik olarak &str'ye çevirir. &text[..i], baştan i baytına kadar olan kısımdır.| Özellik | String | &str |
|---|---|---|
| Sahiplik | verisinin sahibidir | ödünç alır |
| Değiştirme | mut ile büyüyebilir: push_str | yalnızca okuma |
| Oluşturma | String::from("hi"), "hi".to_string() | "hi", &s, &s[0..2] |
| Tipik yeri | yapı alanları, metin oluşturma | fonksiyon parametreleri |
Önemli noktalar
- Her değerin tek bir sahibi vardır; sahip kapsam dışına çıkınca değer düşürülür.
Stringgibi türler atamada ve fonksiyona verilirken taşınır; Copy türleri ise kopyalanır.&okumak için,&mutdeğiştirmek için ödünç alır; sahiplik değişmez.- Aynı anda ya çok sayıda
&ya da tek bir&mutolabilir; referans sahibinden uzun yaşamaz. &strbir metin dilimidir,Stringise kendi verisine sahip, büyüyebilen metindir; parametrelerde&strkullan.
Kendini test et
10 soru. Her doğru cevap XP kazandırır.
let a = String::from("x"); let b = a; kodundan sonra hangi değişken kullanılabilir?