Rust'ta kendi hata tipinizi tanımlamak için bir struct ya da enum oluşturur, ona Debug (genellikle derive ile) ve Display uygular, sonra boş bir impl std::error::Error for HatanizinAdi {} bloğu yazarsınız. Altta yatan başka bir hatayı sarıyorsanız source() metodunu doldurur, ? operatörünün bu hatayı otomatik çevirebilmesi için de From uygularsınız. Farklı hata tiplerini tek tipte toplamanın hızlı yolu ise Box<dyn Error>'dur.

Bu yazı bu dört parçayı, aralarındaki seçimi ve en sık derleme hatalarını çalışan örneklerle anlatıyor. Result, ? operatörü ve unwrap/expect temelleri Rust Result ve hata yönetimi yazısında ele alındığı için burada tekrar edilmiyor. Serinin tamamı için Rust öğrenme rehberi.

İyi bir hata tipi neye benzer?

İyi bir hata tipi neye benzer?

Rust by Example "iyi" bir hata tipinin özelliklerini şöyle sıralar: farklı hataları aynı tipte temsil eder, kullanıcıya düzgün mesajlar gösterir, başka değerlerle kolayca karşılaştırılabilir, hata hakkında bilgi taşıyabilir ve diğer hatalarla iyi birleşir. Örneğin hatayı Err("+ burada kullanılamaz".to_owned()) gibi bir metinle bildirmek kötü bir seçimdir: çağıran kod hatanın türünü ancak metni karşılaştırarak anlayabilir ve hatanın nerede oluştuğu gibi ek bilgileri taşıyamazsınız. Err(GecersizKarakter(c, konum)) gibi bir varyant ise hem eşleştirilebilir hem de bilgi taşır.

std::error::Error trait'i, Result<T, E> içindeki E değerlerinden beklenen temel davranışı tanımlar. Trait'in tanımı pub trait Error: Debug + Display biçimindedir; yani bir tipin Error olabilmesi için önce kendini hem Debug hem Display ile tarif edebilmesi gerekir. Belge hata mesajlarının genellikle küçük harfle başlayan, sonunda noktalama işareti olmayan kısa cümleler olduğunu belirtir; standart kütüphanenin "invalid digit found in string" mesajı buna bir örnektir.

En basit özel hata: struct + Display + Error

Aşağıdaki örnek, geçersiz bir yaş değerini bildiren bir hata tipi tanımlıyor. Debug derive ile geliyor, Display'i elle yazıyoruz ve Error için gövdesi boş bir impl yeterli, çünkü trait'in bütün metotlarının varsayılan uygulaması var:

rust
use std::error::Error;
use std::fmt;

#[derive(Debug)]
struct YasHatasi {
    deger: i32,
}

impl fmt::Display for YasHatasi {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "yaş 0 ile 150 arasında olmalı, gelen değer {}", self.deger)
    }
}

impl Error for YasHatasi {}

fn yas_dogrula(yas: i32) -> Result<i32, YasHatasi> {
    if (0..=150).contains(&yas) {
        Ok(yas)
    } else {
        Err(YasHatasi { deger: yas })
    }
}

fn main() {
    println!("{:?}", yas_dogrula(30));
    match yas_dogrula(200) {
        Ok(y) => println!("geçerli: {y}"),
        Err(e) => {
            println!("Display: {e}");
            println!("Debug: {e:?}");
            println!("to_string: {}", e.to_string());
        }
    }
}
// çıktı: Ok(30)
// çıktı: Display: yaş 0 ile 150 arasında olmalı, gelen değer 200
// çıktı: Debug: YasHatasi { deger: 200 }
// çıktı: to_string: yaş 0 ile 150 arasında olmalı, gelen değer 200

Display kullanıcıya gösterilecek metni, Debug ise geliştiriciye yönelik iç yapıyı verir. Display uygulayan her tipte to_string() de otomatik olarak kullanılabilir. Belge, artık description() metodunun kullanımdan kaldırıldığını (1.42.0'dan beri) ve onun yerine Display ya da to_string() kullanılması gerektiğini, eski cause() metodunun da (1.33.0'dan beri) yerini source()'a bıraktığını belirtir. Display ve Debug uygulamanın ayrıntıları Rust Display ve Debug formatlama yazısında.

Display uygulamayı unutursanız derleyici Error uygulamasını kabul etmez, çünkü trait bunu bir üst trait (supertrait) olarak ister:

rust
use std::error::Error;

#[derive(Debug)]
struct BenimHatam;

impl Error for BenimHatam {}

fn main() {}
// error[E0277]: `BenimHatam` doesn't implement `std::fmt::Display`

Enum ile birden çok hata türü ve source()

Gerçek programlarda bir fonksiyon birkaç farklı nedenle başarısız olabilir. Bunları tek bir enum'un varyantları olarak tanımlamak, çağıranın match ile her durumu ayrı ele almasını sağlar. Bir varyant alt seviyedeki başka bir hatadan kaynaklanıyorsa, o hatayı varyantın içinde saklar ve source() ile dışarı açarsınız. Belge source()'u hataların "soyutlama sınırlarını" geçtiği durumlar için önerir: üst seviye modül kendi hatasını raporlarken, hata ayıklama için alttaki nedeni de erişilebilir bırakır.

rust
use std::error::Error;
use std::fmt;
use std::num::ParseIntError;

#[derive(Debug)]
enum AyarHatasi {
    EksikAlan(String),
    GecersizSayi { alan: String, kaynak: ParseIntError },
}

impl fmt::Display for AyarHatasi {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            AyarHatasi::EksikAlan(ad) => write!(f, "ayar dosyasında `{ad}` alanı yok"),
            AyarHatasi::GecersizSayi { alan, .. } => write!(f, "`{alan}` alanı sayı olmalı"),
        }
    }
}

impl Error for AyarHatasi {
    fn source(&self) -> Option<&(dyn Error + 'static)> {
        match self {
            AyarHatasi::EksikAlan(_) => None,
            AyarHatasi::GecersizSayi { kaynak, .. } => Some(kaynak),
        }
    }
}

fn alan_oku<'a>(metin: &'a str, ad: &str) -> Result<&'a str, AyarHatasi> {
    metin
        .lines()
        .find_map(|satir| satir.strip_prefix(ad)?.strip_prefix('='))
        .ok_or_else(|| AyarHatasi::EksikAlan(ad.to_string()))
}

fn port_oku(metin: &str) -> Result<u16, AyarHatasi> {
    let ham = alan_oku(metin, "port")?;
    ham.trim().parse().map_err(|e| AyarHatasi::GecersizSayi {
        alan: "port".to_string(),
        kaynak: e,
    })
}

fn raporla(sonuc: Result<u16, AyarHatasi>) {
    match sonuc {
        Ok(p) => println!("port: {p}"),
        Err(e) => {
            println!("hata: {e}");
            let mut neden = e.source();
            while let Some(alt) = neden {
                println!("  nedeni: {alt}");
                neden = alt.source();
            }
        }
    }
}

fn main() {
    raporla(port_oku("host=localhost\nport=8080"));
    raporla(port_oku("host=localhost"));
    raporla(port_oku("port=sekiz"));
}
// çıktı: port: 8080
// çıktı: hata: ayar dosyasında `port` alanı yok
// çıktı: hata: `port` alanı sayı olmalı
// çıktı:   nedeni: invalid digit found in string

raporla fonksiyonundaki while let döngüsü, hata zincirini en üstten en alta kadar yürür: her adımda source() bir sonraki nedeni verir, None geldiğinde zincir biter. Bu desen, iç içe geçmiş kütüphane hatalarını kullanıcıya anlamlı bir sırayla göstermenin standart yoludur. source()'un dönüş tipindeki 'static, döndürülen hatanın kısa ömürlü bir referans içermemesini ister; sahipli bir hata tipini alan olarak saklamak bu şartı sağlar.

Belgenin burada önemli bir kuralı var: alttaki hatayı saran bir hata tipinde, alttaki hata ya source() ile döndürülmeli ya da dıştaki hatanın Display çıktısına yazılmalıdır, ikisi birden değil. Örnekte Display yalnızca "port alanı sayı olmalı" diyor ve ayrıştırma hatasının kendi mesajını yazmıyor; o mesaj zincirin bir sonraki halkasında görünüyor. İkisini birden yaparsanız zinciri yazdıran kod aynı bilgiyi iki kez gösterir.

From uygulayarak ? ile otomatik dönüşüm

From uygulayarak ? ile otomatik dönüşüm

Önceki örnekte ayrıştırma hatasını map_err ile elle sarmıştık. ? operatörü hata değerini döndürmeden önce From::from çağırdığı için, hata tipiniz için From<ParseIntError> uygularsanız bu sarmalama otomatik olur. Rust by Example'ın "Wrapping errors" örneğinden uyarlanan aşağıdaki kod, bir tip takma adıyla (type Sonuc<T>) birlikte bu yöntemi gösteriyor:

rust
use std::error::Error;
use std::fmt;
use std::num::ParseIntError;

#[derive(Debug)]
enum HesapHatasi {
    BosListe,
    Ayristirma(ParseIntError),
}

impl fmt::Display for HesapHatasi {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            HesapHatasi::BosListe => write!(f, "liste en az bir eleman içermeli"),
            HesapHatasi::Ayristirma(_) => write!(f, "ilk eleman tam sayıya çevrilemedi"),
        }
    }
}

impl Error for HesapHatasi {
    fn source(&self) -> Option<&(dyn Error + 'static)> {
        match self {
            HesapHatasi::BosListe => None,
            HesapHatasi::Ayristirma(e) => Some(e),
        }
    }
}

impl From<ParseIntError> for HesapHatasi {
    fn from(e: ParseIntError) -> Self {
        HesapHatasi::Ayristirma(e)
    }
}

type Sonuc<T> = std::result::Result<T, HesapHatasi>;

fn ilkinin_iki_kati(liste: &[&str]) -> Sonuc<i32> {
    let ilk = liste.first().ok_or(HesapHatasi::BosListe)?;
    let n: i32 = ilk.parse()?; // ParseIntError, From ile HesapHatasi olur
    Ok(n * 2)
}

fn main() {
    for liste in [vec!["21", "5"], vec![], vec!["yirmi"]] {
        match ilkinin_iki_kati(&liste) {
            Ok(n) => println!("sonuç: {n}"),
            Err(e) => match e.source() {
                Some(k) => println!("hata: {e} (kaynak: {k})"),
                None => println!("hata: {e}"),
            },
        }
    }
}
// çıktı: sonuç: 42
// çıktı: hata: liste en az bir eleman içermeli
// çıktı: hata: ilk eleman tam sayıya çevrilemedi (kaynak: invalid digit found in string)

ilkinin_iki_kati fonksiyonu artık tek satırda iki farklı hata kaynağını ele alıyor: boş liste için ok_or ile doğrudan HesapHatasi::BosListe üretiliyor, ayrıştırma hatası ise ? tarafından From ile sarılıyor. Kendi modülünüzde type Result<T> = std::result::Result<T, BenimHatam>; gibi bir takma ad tanımlamak standart kütüphanede de görülen yaygın bir alışkanlıktır (std::io::Result gibi) ve imzaları kısaltır. From ile Into arasındaki ilişki Rust From, Into ve TryFrom yazısında anlatılıyor.

From uygulamasını unutursanız derleyici açıklayıcı bir hata verir ve tam olarak hangi dönüşümün eksik olduğunu söyler:

rust
#[derive(Debug)]
enum BenimHatam {
    Bos,
}

fn oku(s: &str) -> Result<i32, BenimHatam> {
    if s.is_empty() {
        return Err(BenimHatam::Bos);
    }
    let n = s.parse::<i32>()?;
    Ok(n)
}

fn main() {
    println!("{:?}", oku("3"));
}
// error[E0277]: `?` couldn't convert the error to `BenimHatam`

Hata mesajının devamında derleyici BenimHatam'ın From<ParseIntError> uygulaması gerektiğini ve ?'in hatayı From ile dönüştürdüğünü not olarak ekler. Çözüm ya From uygulamak ya da o satırda map_err ile dönüşümü elle yapmaktır.

Mini örnek: dosya ve ayrıştırma hatalarını tek tipte toplamak

Gerçek bir fonksiyon çoğu zaman hem giriş/çıkış (I/O) hem de ayrıştırma hatası üretebilir. Aşağıdaki örnek bir sayaç dosyasını okuyup içindeki sayıyı döndürüyor. Her iki hata tipi için ayrı bir From uygulaması sayesinde fonksiyon gövdesi yalnızca iki ? içeriyor. Çağıran taraf ise hatanın türüne göre farklı davranıyor: dosya hiç yoksa bunu normal bir durum sayıp sayacı sıfırdan başlatıyor, diğer hataları raporluyor. Örnek, deneme için bozuk bir dosyayı kendisi oluşturup sonunda siliyor:

rust
use std::error::Error;
use std::fmt;
use std::fs;
use std::io;
use std::num::ParseIntError;

#[derive(Debug)]
enum SayacHatasi {
    Io(io::Error),
    Ayristirma(ParseIntError),
}

impl fmt::Display for SayacHatasi {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            SayacHatasi::Io(_) => write!(f, "sayaç dosyası okunamadı"),
            SayacHatasi::Ayristirma(_) => write!(f, "sayaç dosyasındaki değer sayı değil"),
        }
    }
}

impl Error for SayacHatasi {
    fn source(&self) -> Option<&(dyn Error + 'static)> {
        match self {
            SayacHatasi::Io(e) => Some(e),
            SayacHatasi::Ayristirma(e) => Some(e),
        }
    }
}

impl From<io::Error> for SayacHatasi {
    fn from(e: io::Error) -> Self {
        SayacHatasi::Io(e)
    }
}

impl From<ParseIntError> for SayacHatasi {
    fn from(e: ParseIntError) -> Self {
        SayacHatasi::Ayristirma(e)
    }
}

fn sayac_oku(yol: &str) -> Result<u64, SayacHatasi> {
    let metin = fs::read_to_string(yol)?;
    let n = metin.trim().parse::<u64>()?;
    Ok(n)
}

fn main() {
    fs::write("sayac_bozuk.txt", "on iki").unwrap();
    for yol in ["sayac_yok.txt", "sayac_bozuk.txt"] {
        match sayac_oku(yol) {
            Ok(n) => println!("{yol}: {n}"),
            Err(SayacHatasi::Io(e)) if e.kind() == io::ErrorKind::NotFound => {
                println!("{yol}: dosya yok, sayaç 0'dan başlatılıyor");
            }
            Err(e) => println!("{yol}: {e} ({})", e.source().unwrap()),
        }
    }
    fs::remove_file("sayac_bozuk.txt").unwrap();
}
// çıktı: sayac_yok.txt: dosya yok, sayaç 0'dan başlatılıyor
// çıktı: sayac_bozuk.txt: sayaç dosyasındaki değer sayı değil (invalid digit found in string)

Buradaki kritik nokta match kolundaki Err(SayacHatasi::Io(e)) if e.kind() == io::ErrorKind::NotFound desenidir: kendi enum tipiniz sayesinde çağıran, hatanın hem hangi katmandan geldiğini (I/O) hem de alttaki ayrıntıyı (dosya bulunamadı) inceleyebiliyor. Hatayı bir metne çevirmiş olsaydınız bu ayrımı ancak mesajı karşılaştırarak yapabilirdiniz. Display çıktısı yalnızca kendi katmanının mesajını yazıyor, alttaki ayrıntı ise source() üzerinden geliyor; böylece belgenin "ikisinden biri" kuralına da uyuluyor. Dosya işlemlerinin kendisi Rust dosya okuma ve yazma yazısında, match kolundaki if koşulu (guard) ise Rust pattern sözdizimi yazısında anlatılıyor.

Box<dyn Error>: hızlı ve esnek yol

Her hata türü için varyant tanımlamak zahmetlidir ve küçük programlarda gereksiz olabilir. Rust by Example'ın anlattığı alternatif, hataları kutulamaktır: dönüş tipi Result<T, Box<dyn Error>> olduğunda standart kütüphanedeki From uygulaması sayesinde Error uygulayan her tip ? ile otomatik olarak kutuya girer. Sabit bir metinden de .into() ile kutulanmış hata üretebilirsiniz. Bedeli, hatanın gerçek tipinin artık derleme anında değil yalnızca çalışma anında bilinmesidir. Gerekirse downcast_ref ile kutunun içindeki tipi kontrol edebilirsiniz:

rust
use std::error::Error;
use std::fmt;

#[derive(Debug)]
struct KotaAsildi;

impl fmt::Display for KotaAsildi {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "günlük kota aşıldı")
    }
}

impl Error for KotaAsildi {}

fn islem(girdi: &str) -> Result<i32, Box<dyn Error>> {
    if girdi == "kota" {
        return Err(Box::new(KotaAsildi));
    }
    if girdi.is_empty() {
        return Err("girdi boş olamaz".into());
    }
    let n: i32 = girdi.parse()?;
    Ok(n)
}

fn main() {
    for g in ["7", "x", "", "kota"] {
        match islem(g) {
            Ok(n) => println!("{g:?}: {n}"),
            Err(e) => {
                if let Some(k) = e.downcast_ref::<KotaAsildi>() {
                    println!("{g:?}: kota hatası yakalandı: {k}");
                } else {
                    println!("{g:?}: genel hata: {e}");
                }
            }
        }
    }
}
// çıktı: "7": 7
// çıktı: "x": genel hata: invalid digit found in string
// çıktı: "": genel hata: girdi boş olamaz
// çıktı: "kota": kota hatası yakalandı: günlük kota aşıldı

dyn Error bir trait object'tir ve belgeye göre Error trait'i dyn uyumludur (dyn compatible). Trait object'lerin nasıl çalıştığı Rust trait object ve dyn, Box'ın kendisi Rust Box akıllı işaretçi yazısında anlatılıyor. Hata iş parçacıkları arasında taşınacaksa tipin Send ve Sync olduğunu da belirtmeniz gerekir; standart kütüphane Box<dyn Error + Send + Sync> için de aynı downcast metotlarını sunar:

rust
use std::error::Error;
use std::thread;

fn calis(n: i32) -> Result<i32, Box<dyn Error + Send + Sync>> {
    if n < 0 {
        return Err("negatif sayı".into());
    }
    Ok(n * n)
}

fn main() {
    let h = thread::spawn(|| calis(-1));
    match h.join().unwrap() {
        Ok(v) => println!("{v}"),
        Err(e) => println!("iş parçacığından hata: {e}"),
    }
}
// çıktı: iş parçacığından hata: negatif sayı

İş parçacıklarının kendisi Rust thread spawn ve join yazısında, Send ve Sync ise Rust Arc ve Mutex yazısında ele alınıyor.

main'den dönen hatanın görünümü

main bir Result döndürdüğünde ve sonuç Err olduğunda Rust hatayı Error: önekiyle ve hatanın Debug biçimiyle yazdırır, program da sıfırdan farklı bir kodla çıkar. Derive edilmiş Debug çıktısı (BaglantiHatasi { sunucu: "..." } gibi) son kullanıcı için pek okunur değildir. Bunun bir çözümü, Debug'ı derive etmek yerine elle yazıp Display'e yönlendirmektir:

rust
use std::error::Error;
use std::fmt;

struct BaglantiHatasi {
    sunucu: String,
}

impl fmt::Display for BaglantiHatasi {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{} sunucusuna bağlanılamadı", self.sunucu)
    }
}

// main'in Err çıktısı Debug ile yazıldığı için Debug'ı Display'e yönlendiriyoruz
impl fmt::Debug for BaglantiHatasi {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Display::fmt(self, f)
    }
}

impl Error for BaglantiHatasi {}

fn baglan(sunucu: &str) -> Result<(), BaglantiHatasi> {
    Err(BaglantiHatasi { sunucu: sunucu.to_string() })
}

fn main() -> Result<(), Box<dyn Error>> {
    baglan("db.ornek.local")?;
    Ok(())
}
// çıktı: Error: db.ornek.local sunucusuna bağlanılamadı
// (çıkış kodu: 1)

Bu yaklaşımın bir bedeli var: hata ayıklarken iç yapıyı görmek istediğinizde {:?} artık alanları göstermez. Alternatif, main'i kısa tutup asıl işi Result döndüren bir calistir() fonksiyonuna vermek, main'de hatayı yakalayıp eprintln!("hata: {e}") ile yazdırmak ve std::process::exit(1) ile çıkmaktır. Bu desen The Rust Book'un komut satırı projesinde de kullanılır ve Rust komut satırı argümanları yazısında anlatılıyor.

Hangi yaklaşımı seçmeli?

Hangi yaklaşımı seçmeli? Az kod, her hata ? ile geçer, Kendi enum hata tipiniz, Tek struct hata, String hata
YaklaşımAvantajDezavantajUygun olduğu yer
Box<dyn Error>Az kod, her hata ? ile geçerTip çalışma anında belli olur, match ile ayrıştırmak zorUygulamalar, betikler, main ve prototipler
Kendi enum hata tipinizÇağıran her durumu match ile ele alabilirDisplay, Error ve From için daha fazla kodKütüphaneler ve genel API
Tek struct hataBasit, ek bilgi taşıyabilirTek bir başarısızlık türü için uygundurDoğrulama gibi tek nedenli hatalar
String hataEn hızlı yazılanTürüne göre ayırt edilemez, birleşmezYalnızca kısa denemeler

Genel bir kural olarak, başkalarının kullanacağı bir kütüphane yazıyorsanız çağıranın hataları ayırt edebilmesi için kendi enum tipinizi tercih edin. Kendi uygulamanızın en üst katmanında ise Box<dyn Error> çoğu zaman yeterlidir. Rust by Example, özel hata tiplerinin getirdiği tekrar eden kodu azaltan kütüphanelerin de bulunduğunu not eder; bunlar standart kütüphanenin parçası değildir, ayrıntıları için https://docs.rs adresine bakabilirsiniz.

Sık yapılan hatalar

  • Display uygulamadan Error yazmak: E0277 verir; Error trait'i Debug + Display ister.
  • From uygulamadan ? kullanmak: "couldn't convert the error" hatası alırsınız. From ekleyin ya da map_err kullanın.
  • Alt hatayı hem Display'de hem source()'ta göstermek: Belge ikisinden yalnızca birini önerir; aksi hâlde zincir yazdırılırken mesaj tekrarlanır.
  • Hatayı yalnızca metin olarak saklamak: Çağıran hatanın türünü ayırt edemez. Ayırt edilmesi gereken durumlar için enum varyantı kullanın.
  • Kullanımdan kalkmış description() ya da cause()'u uygulamak: Yerine Display ve source() kullanın.

Sık Sorulan Sorular

Error trait'ini uygulamak zorunlu mu?

Hayır. Result<T, E>'deki E herhangi bir tip olabilir. Ancak Error uygulamak, hatanızın Box<dyn Error>'a çevrilebilmesini, source() zincirine katılabilmesini ve main'den döndürülebilmesini sağlar; başkalarının kullanacağı kodda uygulamanız önerilir.

Kendi enum hata tipim Box<dyn Error> döndüren bir fonksiyonda ? ile kullanılabilir mi?

Evet. Tipiniz Error uyguladığı sürece standart kütüphanedeki dönüşüm onu ? ile otomatik olarak Box<dyn Error>'a çevirir. Yukarıdaki BaglantiHatasi örneğinde main tam olarak bunu yaptı: baglan kendi hata tipini döndürdü, main ise kutulanmış hata bekliyordu. Bu sayede kütüphane katmanında ayrıntılı enum tipleri, uygulamanın en üst katmanında ise tek bir kutulanmış tip kullanan karma bir düzen kurabilirsiniz. Ters yönde, yani kutulanmış bir hatayı kendi tipinize geri çevirmek için downcast gerekir.

Kutulanmış hatanın gerçek tipini nasıl öğrenirim?

dyn Error üzerinde is::<T>() tip kontrolü yapar, downcast_ref::<T>() bir Option<&T> döndürür, Box<dyn Error> üzerindeki downcast::<T>() ise kutuyu somut tipe çevirmeyi dener. Bu işlemin çalışması için tipin 'static olması gerekir.

Hata tipime PartialEq eklemeli miyim?

Testlerde assert_eq!(sonuc, Err(BenimHatam::Bos)) gibi karşılaştırmalar için kullanışlıdır. Ancak sardığınız alt hata tipi PartialEq uygulamıyorsa derive çalışmaz. Rust by Example da kolay karşılaştırılabilirliği iyi bir hata tipinin özellikleri arasında sayar. Test yazımı Rust test yazma yazısında.

Hata zincirinin tamamını tek seferde yazdıran hazır bir araç var mı?

Belgede bir hatayı ve kaynaklarını yazdıran Report tipi ile kaynakları gezen sources() metodu yer alıyor, ancak ikisi de şu an yalnızca nightly sürümde kullanılabilen deneysel API'lerdir. Kararlı Rust'ta yukarıdaki while let döngüsüyle zinciri kendiniz gezebilirsiniz.

Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.

İlgili içerikler: Rust öğrenme rehberi · Result ve hata yönetimi · From ve Into · Trait object · Display ve Debug · Komut satırı uygulaması