---
title: "Türetilen Trait'ler"
source: 'https://academia.sh/tr/kurslar/rust-soyutlama/turetilen-traitler'
course: "Trait'ler, Genellikler ve Hata Yönetimi"
language: tr
updated: '2026-09-13T05:09:26+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - "Türetme özniteliğinin bir trait'i elle yazmadan gerçekleştirdiğini gösterir"
    - 'Elle yazılan bir gövdenin koşum sayısının sayılabildiğini, türetilmiş bir gövdenin sayılamadığını karşılaştırarak açıklar'
    - 'Aynı türetmenin farklı veri düzenlerinde farklı sonuçlar verebildiğini koşturarak gösterir'
---

# Türetilen Trait'ler

Bir öznitelik satırı, bir trait'i elle yazmadan gerçekleştirebilir — türetme; elle yazılan gövde koşum defterine bir sayaç çağrısı koyabilirken, türetilmiş gövde kaynakta hiç yazılı olmadığı için sayılamaz ve yalnız davranışıyla gözlemlenebilir; üstelik aynı türetme iki farklı veri düzeninde iki farklı sonuç verir.

Önceki dört ders elle yazılan gövdeleri ölçtü: bir trait'in varsayılan gövdesi, sınırlı bir
genel gövde, ilişkili tip taşıyan bir gövde, statik ya da dinamik çağrılan bir gövde — hepsi
kaynakta bir yerde, bir `fn` satırının altında duruyordu. Bir trait gerçekleştirimi bazen hiç
elle yazılmaz: `#[derive(...)]` öznitelik satırı, derleyiciye "bu trait'i bu tip için sen
üret" der ve gövdeyi kaynağa hiç yazmadan ortaya çıkarır. Bu ders bu türden bir gövdenin
kaç kez koştuğunu soruyor — ve bu kez soruya tam bir sayıyla yanıt verilemediğini gösteriyor.

## Elle Yazılan ile Türetilmiş Arasındaki Fark

Bir tip için eşitlik karşılaştırması iki yolla kurulabilir: `impl PartialEq for Tip` bloğunu
elle yazarak, ya da `#[derive(PartialEq)]` satırını tipin üstüne koyarak. İkisi de aynı
sonucu üretir — iki değerin alan alan eşit olup olmadığını söyler — ama kaynaktaki
karşılıkları farklı.

```rust
// kere.rs — kesit: say/kere defteri, elle yazilan esitlik govdesi.

use std::cell::RefCell;
use std::collections::BTreeMap;
use std::rc::Rc;

pub type Defter = Rc<RefCell<BTreeMap<String, u32>>>;

pub fn say(defter: &Defter, ad: &str) {
    *defter.borrow_mut().entry(ad.to_string()).or_insert(0) += 1;
}

pub fn kere(defter: &Defter, ad: &str) -> u32 {
    *defter.borrow().get(ad).unwrap_or(&0)
}

// Elle yazilan gerceklestirim: govde kaynakta duruyor, sayilabiliyor.
pub struct ElleEsit {
    pub x: i32,
    pub y: i32,
    pub defter: Defter,
}

impl PartialEq for ElleEsit {
    fn eq(&self, oteki: &Self) -> bool {
        say(&self.defter, "elle-esitlik-govdesi");
        self.x == oteki.x && self.y == oteki.y
    }
}

// Turetilmis gerceklestirim: govde kaynakta yok, derleyici alan alan karsilastirma uretiyor.
#[derive(PartialEq)]
pub struct TuretilmisEsit {
    pub x: i32,
    pub y: i32,
}
```

`ElleEsit`in `eq` yöntemi, kaynakta iki satırlık bir gövde taşıyor: önce bir sayma çağrısı,
sonra alan alan karşılaştırma. `TuretilmisEsit` ise hiçbir `impl PartialEq` bloğu taşımıyor —
tek satırı `#[derive(PartialEq)]` ve bu satır bir yöntem gövdesi değil, derleyiciye bir
**talimat**. Derleyici bu talimatı okuyunca kendi `eq` gövdesini üretiyor; bu gövde
`ElleEsit`inkiyle aynı işi yapıyor (`x` alanlarını ve `y` alanlarını karşılaştırmak) ama
kaynakta hiçbir satırda görünmüyor.

Tek bir `#[derive(...)]` satırı birden fazla trait'i aynı anda üretebilir; parantez içine
virgülle ayrılmış trait adları yazılır. Bu kursta zaten görülen `Clone` da bu yolla
türetilebilir, `Debug` (bir değeri okunabilir bir metin kalıbına döken trait) da:

```rust
// turetme-debug.rs — Debug turetmesi, alanlari otomatik bir metin kalibina donusturur.
#[derive(Debug, Clone, PartialEq)]
struct Nokta {
    x: i32,
    y: i32,
}

fn main() {
    let a = Nokta { x: 3, y: 5 };
    let b = a.clone();
    println!("{:?}", a);
    println!("esit_mi={}", a == b);
}
```

```
Nokta { x: 3, y: 5 }
esit_mi=true
```

Üç trait de (`Debug`, `Clone`, `PartialEq`) tek satırda türetildi ve üçünün de gövdesi
kaynakta görünmüyor. `{:?}` çıktısı, `Debug`in ürettiği gövdenin alan adlarını ve
değerlerini kendiliğinden bir araya getirdiğini gösteriyor — bu kalıp da elle yazılmadı, tıpkı
`eq` gibi derleyici tarafından üretildi. Bu üç trait birlikte türetilebiliyor çünkü üçü de
aynı ilkeye dayanıyor: yapının her alanı için aynı işlemi (yazdırmak, kopyalamak,
karşılaştırmak) sırayla uygulamak. Bu ortak ilke, ilerleyen bir derste (dizileştirme)
tekrar karşımıza çıkacak.

## Sayılabilen ve Sayılamayan

```rust
// turetme-sayilamaz.rs — elle yazilan govde sayilir, turetilmis govde sayilamaz.
mod kere;
use kere::{kere, Defter, ElleEsit, TuretilmisEsit};
use std::cell::RefCell;
use std::collections::BTreeMap;
use std::rc::Rc;

fn main() {
    let defter: Defter = Rc::new(RefCell::new(BTreeMap::new()));
    let a = ElleEsit { x: 1, y: 2, defter: Rc::clone(&defter) };
    let b = ElleEsit { x: 1, y: 2, defter: Rc::clone(&defter) };
    let c = ElleEsit { x: 9, y: 9, defter: Rc::clone(&defter) };

    let esit_mi = a == b;
    let esit_degil_mi = a == c;
    println!("elle: esit_mi={} esit_degil_mi={}", esit_mi, esit_degil_mi);
    println!("elle-esitlik-govdesi={}", kere(&defter, "elle-esitlik-govdesi"));

    // Turetilmis PartialEq'in govdesi kaynakta yazili degil - bu yuzden bir sayma
    // cagrisi icine koyamayiz. Yalnizca davranisini gozlemleyebiliriz.
    let p = TuretilmisEsit { x: 1, y: 2 };
    let q = TuretilmisEsit { x: 1, y: 2 };
    let r = TuretilmisEsit { x: 9, y: 9 };
    println!("turetilmis: esit_mi={} esit_degil_mi={}", p == q, p == r);
}
```

```
elle: esit_mi=true esit_degil_mi=false
elle-esitlik-govdesi=2
turetilmis: esit_mi=true esit_degil_mi=false
```

**TR10.** `elle-esitlik-govdesi` iki kez koştu — `a == b` ve `a == c` çağrılarının her ikisi
de `eq` gövdesini tetikledi, çünkü gövdenin içine bir sayma çağrısı elle yerleştirildi. Bu
satır **her seferinde** sınıfına giriyor: `==` işleci her kullanıldığında kaçınılmaz biçimde
çalışıyor. `TuretilmisEsit` için aynı satırı yazamıyoruz — derleyicinin ürettiği gövdenin
içine hiçbir kaynak satırı ekleyemediğimiz için, kaç kez çalıştığını gösteren bir sayaç
koyamıyoruz. `p == q` ve `p == r` çağrılarının **ikisinin de** doğru sonucu verdiğini
görebiliyoruz (davranış gözlemi), ama bu iki çağrının arkasındaki gövdenin kaç kez
tetiklendiğini koşum defterine yazdıramıyoruz. Bu, kaynakta yazılı olmayan bir gövdenin
kursun üç sınıfından **hiçbirine kesin biçimde yerleştirilemediğini** gösteriyor — çalıştığı
kesin (çağrı her yapıldığında bir sonuç dönüyor), ama koşum sayısı bu yöntemle ölçülemez.

Nesneye Dayalı Java kursu, kayıt (record) tipinin eşitlik ve metin gösterimini otomatik
kurduğunu göstermişti — orada ölçülen kararı hangi tipin verdiğiydi, kaydın kendi ürettiği
gövdenin çalışıp çalışmadığı değil. Bu ders benzer bir otomatik üretime bakıyor, ama farklı
bir soru soruyor: üretilen bu gövde, kursun saymayı esas alan yöntemine göre sayılabilir mi?
Yanıt hayır — ders bunu açıkça söylüyor, bir sayı uydurmuyor.

Türetilmiş bir gövdenin sayılamaması, onun rastgele ya da öngörülemez olduğu anlamına
gelmiyor — tam tersine, `#[derive(PartialEq)]`in ne üreteceği tamamen belirlenimci: yapının
alanlarını bildirim sırasıyla tek tek karşılaştırır, hepsi eşitse `true`, biri bile
eşitsizse `false` döner. Bu kural her `#[derive(PartialEq)]` için aynıdır ve yapı
bildirimine bakarak koşturmadan bile önceden söylenebilir. Sayılamayan şey davranışın
kendisi değil, o davranışın çalışma zamanındaki **çağrı sayısı**: kaç kez `eq` çalıştığını
görmek istiyorsak koşum defterine bir satır eklememiz gerekiyor ve türetilmiş kaynakta
eklenecek bir satır yok.

"Gövde kaynakta yok" demek, "hiçbir gövde derlenmiyor" demek değil. `#[derive(...)]`
satırı, derleme sırasında `impl` bloğuna benzer bir kod parçası **üretiyor** ve bu üretilmiş
kod, elle yazılmış bir `impl` bloğuyla aynı yolla derleniyor — üretim, derlemenin geri
kalanından önce, ayrı bir aşamada oluyor. Yazan kişinin gördüğü kaynakta bu üretilmiş kod
hiç görünmüyor; yalnız `#[derive(PartialEq)]` satırı görünüyor, ürettiği onlarca satırlık
karşılaştırma mantığı görünmüyor. Bu ders "yazılmayan bir gövde de koşar" derken tam bunu
kastediyor: koşan şey var, gerçekten çalışıyor, ama yazan kişinin **okuduğu** kaynakta bir
karşılığı yok. Sayaç çağrısı ekleyemememizin nedeni de bu — sayaç eklemek için önce
üzerine ekleme yapılacak bir kaynak satırına ihtiyaç var ve türetilmiş gövdede öyle bir
satır elimizde değil.

## Aynı Türetme, Farklı Veri Düzeni, Farklı Sonuç

Türetmenin kaynakta gövdesi olmaması, her tipte aynı anlama geldiği izlenimini
uyandırabilir. Değil: aynı `#[derive(Clone)]` satırı, iki farklı veri düzeninde iki farklı
davranış üretiyor. `derive` her zaman "alan alan aynı işlemi uygula" der, ama "aynı işlem"in
ne anlama geldiği alanın kendi tipine bağlı — bir `i32` için kopyalamak yeni bir sayı
yazmaktır, bir `Rc<...>` için kopyalamak sayaç artırıp aynı hücreyi paylaşmaktır.

```rust
// turetme-duzen.rs — ayni turetme, iki veri duzeninde iki farkli sonuc verir.
use std::cell::RefCell;
use std::rc::Rc;

#[derive(Clone)]
struct Bagli {
    veri: Rc<RefCell<i32>>,
}

#[derive(Clone)]
struct Ayrik {
    veri: i32,
}

fn main() {
    let a = Bagli { veri: Rc::new(RefCell::new(1)) };
    let b = a.clone();
    *a.veri.borrow_mut() += 41;
    println!("bagli klon paylasiyor mu: {}", *b.veri.borrow() == 42);

    let c = Ayrik { veri: 1 };
    let mut d = c.clone();
    d.veri += 41;
    println!("ayrik klon paylasiyor mu: {}", c.veri == d.veri);
}
```

```
bagli klon paylasiyor mu: true
ayrik klon paylasiyor mu: false
```

**TR11.** `Bagli`nin klonu, kaynaktaki değeri **paylaşıyor**: `a` üzerinden yapılan
değişiklik `b`de de görünüyor, çünkü `Rc<RefCell<i32>>` alanının türetilmiş klonu yalnız
sayacı bir artırıp aynı hücreye ikinci bir referans veriyor — Sahiplik ve Bellek Modeli
kursunun Referans Sayımı dersinde kurulan davranış. `Ayrik`in klonu ise **bağımsız**: `d`
üzerinde yapılan değişiklik `c`yi hiç etkilemiyor, çünkü `i32` alanının türetilmiş klonu
kendi başına bir kopya üretiyor. `#[derive(Clone)]` satırı ikisinde de birebir aynı, ama
sonuç veri düzenine göre ayrışıyor — türetme "alan alan klonla" demenin kısa yolu, alanın
kendisinin ne anlama geldiğine karışmıyor.

Bu ayrım, elle yazılan bir gövdeyle türetilmiş bir gövde arasındaki farkı bir kez daha
gösteriyor: elle yazılan bir `impl Clone`, isterse `Bagli` için de bağımsız bir kopya
üretecek biçimde yazılabilirdi — içindeki `RefCell`in değerini okuyup yeni bir `Rc` kurarak.
Türetilmiş gövde bu seçeneği sunmuyor; her zaman "alanları olduğu gibi klonla" diyor, alanın
kendi `Clone` gerçekleştirimi ne yapıyorsa onu miras alıyor. Bir tipin klonunun paylaşımlı mı
bağımsız mı olacağına türetme değil, alan tiplerinin seçimi karar veriyor.

Türetmenin bir de sessiz bir önkoşulu var: bir yapı için `#[derive(PartialEq)]` yazmak,
yapının **her alanının** kendi başına `PartialEq`i gerçekleştirmiş olmasını gerektiriyor —
derleyici alan alan karşılaştırma üretirken her alan için `==` çağırıyor ve bu çağrının
derlenebilmesi için alanın kendi tipinin karşılaştırılabilir olması şart. `Nokta`nın `x` ve
`y` alanları `i32` olduğu, `i32` de `PartialEq`i zaten taşıdığı için türetme sorunsuz
derleniyor. Alanlardan biri karşılaştırılamayan bir tip taşısaydı (örneğin bir fonksiyon
işaretçisi), aynı `#[derive(PartialEq)]` satırı derleyici tarafından reddedilirdi — bu redd
de, kursun genel kuralı gereği, bir kod bloğuna konmuyor; yukarıdaki `Nokta` ve `ElleEsit`
örnekleri zaten kabul edilen karşılığı gösteriyor: yalnız karşılaştırılabilir alanlar
taşıyan yapılar.

## Sınırlayıcı Ölçüm

Türetme her tipte aynı anlama gelmiyor. Aynı `#[derive(Clone)]` bir tipte paylaşımlı bir
kopya, başka bir tipte bağımsız bir kopya üretebiliyor; aynı `#[derive(PartialEq)]` bir
tipte iki alanı, başka bir tipte on alanı karşılaştırabiliyor — üretilen gövdenin **ne
yaptığı**, üzerine kurulduğu tipin alanlarına bağlı. Bu ders türetilmiş gövdenin kaç kez
koştuğunu sayamadığı gibi, iki farklı türetimin aynı işi yaptığını da varsaymıyor; yalnız
ikisinin de derleyici tarafından üretildiğini ve davranışının koşturularak gözlemlenebildiğini
gösteriyor. Kursun ölçüm yöntemi burada açık bir sınıra çarpıyor: kaynakta bir sayma çağrısı
yazılamayan her yerde, sayı yerine **davranış karşılaştırması** devreye giriyor.

Bu sınırın pratik bir sonucu var: türetilmiş bir gövdeye güvenmek, o gövdenin **tasarımını**
anlamayı gerektiriyor, çünkü çalışma zamanında onu izlemenin bir yolu yok. `Bagli` tipindeki
`Rc<RefCell<i32>>` alanı için `#[derive(Clone)]` yazmak, "bu tipin kopyası paylaşımlı olsun"
kararını **görünmez** biçimde alıyor — bu karar yapı bildirimini okuyan birine `derive`
satırından değil, alanın kendi tipinden belli oluyor. Elle yazılan bir `impl Clone` bu kararı
gövdenin içinde açıkça gösterebilirdi (bir referans mı kopyalanıyor, bir değer mi); türetilmiş
gövde bu kararı alan tipine devrediyor ve kaynakta ayrıca yazmıyor. Bu, türetmenin kısayolunun
bedeli: kaynak kısalıyor, ama kaynağı okuyanın davranışı anlamak için alan tiplerine kadar
inmesi gerekiyor.

Önceki dört ders, gövde her zaman kaynakta bir `fn` satırının altında durduğu için, koşum
sayısını `say` çağrısıyla doğrudan ölçebiliyordu. Bu ders o varsayımı kırıyor: gövde kaynakta
yok, ama davranış var ve doğrulanabilir. Kursun ölçüm yöntemi, sayamadığı yerde susmayı
seçiyor — bir sayı uydurmak yerine, "burada sayı yok" diyor.

## Özet

- Türetme özniteliği (`#[derive(...)]`), bir trait'i elle yazmadan, derleyiciye ürettirerek
  gerçekleştirir; kaynakta bir yöntem gövdesi bırakmaz.
- Elle yazılan gövde (`elle-esitlik-govdesi`) her seferinde sınıfına girer ve sayılabilir —
  bu derste iki kez koştu; türetilmiş gövde her çağrıldığında çalışır ama kaynakta gövdesi
  olmadığı için bu koşum sayılamaz.
- Sayılamayan bir gövdenin davranışı yine de koşturularak gözlemlenebilir: doğru sonucu
  verip vermediği görülebilir, kaç kez çalıştığı görülemez.
- Aynı türetme iki farklı veri düzeninde iki farklı sonuç verebilir — `Rc<RefCell<...>>`
  alanı olan bir tipte paylaşımlı, düz bir sayısal alanda bağımsız bir kopya üretir.

## Sonraki Adım

Bu ders, bir gövdenin **hiç yazılmamış olsa bile** çalıştığını gösterdi. Kursun son dersi
başka bir görünmezliğe bakıyor: bir işlecin (`+` gibi) çağrıldığı yer kaynakta hiç görünmez,
yalnız işlecin kendisi görünür. Sıradaki ders bu görünmez çağrının kaç kez koştuğunu, üç
terimli bir toplamı koşturarak sayıyor.
