Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

if let Geçici Kapsamı

Özet

  • if let $pat = $expr { .. } else { .. } ifadesinde, $expr değerlendirilirken oluşan geçici değerler artık else dalına girdikten sonra değil, programa else dalına girmeden önce düşer.

Ayrıntılar

2024 sürümü, bir if let ifadesindeki scrutinee1 içinde bulunan geçici değerlerin düşme kapsamını değiştirir. Amaç, geçicinin gereğinden uzun yaşamasından doğan beklenmedik davranışları azaltmaktır.

2024’ten önce geçiciler if let ifadesinin ötesine uzatılabiliyordu. Örneğin:

#![allow(unused)]
fn main() {
// 2024'ten önce
use std::sync::RwLock;

fn f(value: &RwLock<Option<bool>>) {
    if let Some(x) = *value.read().unwrap() {
        println!("deger {x}");
    } else {
        let mut v = value.write().unwrap();
        if v.is_none() {
            *v = Some(true);
        }
    }
    // <--- 2021'de okuma kilidi burada düşer
}
}

Bu örnekte value.read() çağrısıyla oluşturulan geçici okuma kilidi, if let ifadesi bitene kadar, yani else bloğundan sonrasına kadar düşmez. else bloğu çalışırsa, yazma kilidi almaya çalıştığında kilitlenmeye neden olur.

2024 sürümü, geçicilerin ömrünü then-bloğu tamamen değerlendirildiği ya da program denetiminin else bloğuna geçtiği noktaya kadar kısaltır.

#![allow(unused)]
fn main() {
// 2024 ile birlikte
use std::sync::RwLock;

fn f(value: &RwLock<Option<bool>>) {
    if let Some(x) = *value.read().unwrap() {
        println!("deger {x}");
    }
    // <--- 2024'te okuma kilidi burada düşer
    else {
        let mut v = value.write().unwrap();
        if v.is_none() {
            *v = Some(true);
        }
    }
}
}

Geçici kapsamların nasıl genişletildiğine dair daha fazla bilgi için geçici kapsam kurallarına bakın. Kuyruk ifadelerine yapılan benzer bir değişiklik için kuyruk ifadesi geçici kapsamı bölümüne göz atın.

Taşıma

if let ifadesini match ile yeniden yazmak her zaman güvenlidir. match scrutinee’sinin geçicileri match ifadesinin sonrasına, genelde ifadenin bittiği noktaya kadar uzatılır. Bu, if letin 2021’deki davranışıyla aynıdır.

if_let_rescope lint’i, bu değişiklik yüzünden bir ömür sorunu doğduğunda ya da if let scrutinee’sinden özel ve sıradan olmayan bir Drop yıkıcısına sahip geçici değer üretildiğini tespit ettiğinde bir düzeltme önerir. Örneğin yukarıdaki örnek, cargo fix önerisi kabul edildiğinde şöyle yeniden yazılabilir:

#![allow(unused)]
fn main() {
use std::sync::RwLock;
fn f(value: &RwLock<Option<bool>>) {
    match *value.read().unwrap() {
        Some(x) => {
            println!("deger {x}");
        }
        _ => {
            let mut s = value.write().unwrap();
            if s.is_none() {
                *s = Some(true);
            }
        }
    }
    // <--- Okuma kilidi hem 2021'de hem 2024'te burada düşer
}
}

Bu özel örnekte, az önce bahsedilen kilitlenme yüzünden bu muhtemelen istediğiniz şey değildir. Ancak bazı senaryolar, geçicilerin else dalının ötesinde tutulduğunu varsayıyor olabilir; böyle bir durumda eski davranışı korumak isteyebilirsiniz.

if_let_rescope lint’i, otomatik sürüm taşımasına dahil olan rust-2024-compatibility lint grubunun parçasıdır. Kodunuzu Rust 2024 ile uyumlu hale getirmek için şunu çalıştırın:

cargo fix --edition

Taşıma sonrasında if letten matche çevrilen tüm değişiklikleri gözden geçirmeniz ve geçicilerin ne zaman düşmesi gerektiği açısından hangi davranışa ihtiyaç duyduğunuza karar vermeniz önerilir. Eğer değişikliğin gereksiz olduğuna karar verirseniz dönüşümü yeniden if lete çevirebilirsiniz.

Sürüm taşımasını yapmadan bu uyarıları elle incelemek isterseniz lint’i şu şekilde etkinleştirebilirsiniz:

#![allow(unused)]
fn main() {
// Elle taşıma yapmak için bunu crate köküne ekleyin.
#![warn(if_let_rescope)]
}

  1. scrutinee, if let ifadesinde eşleştirilen ifadedir.