---
title: Yapılar
source: 'https://academia.sh/tr/kurslar/rust-temelleri/yapilar'
course: 'Rust Temelleri'
language: tr
updated: '2026-09-13T05:09:29+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Yapı değeri kurmanın üç yazımının da birer ifade olduğunu gösterir'
    - 'struct bildiriminin bir öğe olduğunu ve tek başına değer üretmediğini açıklar'
    - 'Yöntem ile ilişkili fonksiyonu alıcının varlığına göre ayırt eder'
    - 'Adlandırılmış yapı ile demet yapısında alan sırasının kimliğini karşılaştırır'
---

# Yapılar

Aynı Nokta değeri üç ayrı yazımla kuruluyor — tam yazım, güncelleme sözdizimi, ilişkili fonksiyon — ve üçü de bir ifade olarak değer üretiyor; struct bildiriminin kendisi hiçbir değer üretmiyor, yalnızca sonraki satırların kullanacağı bir ad tanıtıyor.

Denetim Akışı dersi beş akış biçiminin değer üretip üretmediğini tek tek ölçtü: `if` ve
`match` birer ifadeydi, `loop` yalnızca `break` ile değer taşıdı, `while` ile `for` hiçbir
zaman değer vermedi. Bu ders aynı soruyu farklı bir malzemeye taşıyor. Artık akış biçimleri
değil veri tipleri var ve soru değişmiyor: bir tipten değer kurmak bir ifade mi, yoksa
tipin kendisini kaynağa yazmak mı?

Rust'ta birden çok alanı tek bir tip altında toplamanın yolu yapıdır (struct). Bu ders, bir
yapının **bildirilmesi** ile o yapıdan bir **değer kurulması** arasındaki farkı üç ayrı
yazımla ölçüyor — tam yazım, güncelleme sözdizimi ve ilişkili fonksiyon — ve üçünün de aynı
sınıfa düştüğünü gösteriyor. Bildirimin kendisi hiçbir zaman o sınıfa girmiyor. Dersin
ikinci yarısı ise bildirimin içindekilere, yani alanlara döner: aynı alan kümesi iki farklı
yapı biçiminde — adı olan ve adı olmayan — ne kadar farklı davranıyor, bu da ayrıca
ölçülüyor.

## Bildirim Bir Öğedir, Değer Kurmak Bir İfadedir

`struct Nokta { x: i32, y: i32 }` satırı çalıştırıldığında hiçbir şey üretmez. Bu satır bir
hesaplama değil, derleyiciye bir ad tanıtan bir bildirimdir: sonraki satırların `Nokta`
adını kullanabilmesinin önkoşuludur, ama kendisi bir değer değildir. Bir önceki dersin
terimiyle bu bir **öğedir** — kaynağın herhangi bir noktasında "çalışmaz", yalnızca orada
durur ve derleyicinin bileceği bir tip ekler.

Buna karşılık `Nokta { x: 3, y: 4 }` yazımı çalıştırıldığında bir değer üretir: iki tam
sayıyı alıp bunları `Nokta` tipinde tek bir değere paketler. Bu bir **ifadedir** — sonucu
bir değişkene bağlanabilir, bir fonksiyona argüman olarak geçirilebilir, bir listeye
eklenebilir. Aradaki fark tam olarak önceki derste kurulan ayrımın kendisidir: biri
değerlendirilmeden orada durur, öbürü değerlendirilip bir değer verir.

**RV1.** — Bir `struct` bildiriminin tek başına hiçbir çıktı üretmediği iddiası burada
ayrı bir koşumla değil, aşağıdaki programın kendisiyle doğrulanıyor: `struct Nokta { ... }`
satırı `main` içinde değil, `main`den önce duruyor ve hiçbir yazdırma çağrısı o satırı
tetiklemiyor. Program çalıştığında görünen tek çıktı, `Nokta` adının **kullanıldığı**
satırlardan geliyor.

Bu ayrımın altında yatan neden, iki satırın derleyici için farklı zamanlarda işlenmesidir.
Bir bildirim derleme zamanında (compile time) okunur: derleyici `Nokta` adını, alanlarını
ve tiplerini tabloya kaydeder, ama bu kayıt işlemi programın çalışma zamanında (runtime)
hiçbir iz bırakmaz. Bir değer kurma yazımı ise çalışma zamanında işler: `Nokta { x: 3, y:
4 }` satırı çalıştığında bellekte gerçekten iki tam sayı bir araya getirilir. `let` ile
kurulan bir bağlamanın (Değişkenler ve Değişmezlik dersinin konusu) çalışma zamanında
gerçekleşmesiyle aynı düzendedir bu — farkı, bağlamanın soluna bir öğe değil bir ifade
gelmek zorunda olmasıdır.

Bu, üç sınıfın en berrak biçimde ayrıştığı yerlerden biridir. Bir **deyim** hâlâ
değerlendirilir — yalnızca sonucu `()`e düşer ya da atılır — ama bir **öğe** hiç
değerlendirilmez; kaynakta durduğu yerde "çalışan" bir şey yoktur. `struct` bildirimi
bu üçüncü kategoriye girer: program çalışırken üzerinden geçilen bir adım değil,
derleyicinin kaynağı okurken bir kez işlediği bir kayıttır.

Aşağıdaki koşum, aynı `Nokta` tipinden değer kurmanın üç ayrı yolunu yan yana koyuyor.

```rust
// yapi_kurma.rs — struct bildirimi bir oge, yapi degeri kurmak bir ifadedir
struct Nokta {
    x: i32,
    y: i32,
}

impl Nokta {
    fn koken() -> Nokta {
        Nokta { x: 0, y: 0 }
    }

    fn boyut(&self) -> i32 {
        self.x.abs() + self.y.abs()
    }
}

fn main() {
    let a = Nokta { x: 3, y: 4 };
    println!("{:<21}: x={} y={}", "tam yazim", a.x, a.y);

    let b = Nokta { y: 9, ..a };
    println!("{:<21}: x={} y={}", "guncelleme sozdizimi", b.x, b.y);

    let c = Nokta::koken();
    println!("{:<21}: x={} y={}", "iliskili fonksiyon", c.x, c.y);

    println!("{:<21}: {}", "yontem sonucu", b.boyut());
}
```

```
tam yazim            : x=3 y=4
guncelleme sozdizimi : x=3 y=9
iliskili fonksiyon   : x=0 y=0
yontem sonucu        : 12
```

**Tam yazım** bütün alanları tek tek verir: `x` ve `y` açıkça yazılır, sonuç `x=3 y=4`
olan bir değerdir. **Güncelleme sözdizimi** (`..a`) bunun bir kısaltmasıdır: yalnızca `y`
alanı yeniden verilir, geri kalan alanlar `a`dan kopyalanır. Sonuç yine tek bir çağrıda
üretilen bir `Nokta` değeridir — sözdizimi farklı, sınıf aynı. **İlişkili fonksiyon**
(`Nokta::koken()`) ise bambaşka bir yoldan aynı sınıfa varır: `x` ve `y` hiç yazılmadan,
işlev çağrısının kendisi bir `Nokta` üretir. Üç yazımın ortak noktası, üçünün de `let` ile
bir ada bağlanabilmesidir — bu, bir ifadenin tanımı gereği zaten mümkündür, bir öğe için ise
anlamsızdır.

## Yöntem ile İlişkili Fonksiyon: Alıcının Varlığı

`Nokta::koken()` ile `b.boyut()` çağrıları görünüşte benzer: ikisi de `impl Nokta` bloğu
içinde tanımlı, ikisi de bir değer döndürüyor. Aralarındaki fark çağrı sözdiziminde
görünür ve tek bir noktaya iniyor: **alıcının varlığı**.

`koken` fonksiyonunun imzasında `self` yoktur; bu yüzden tip adıyla çağrılır
(`Nokta::koken()`) ve bir örnek gerektirmez. Rust'ın kendi terimiyle bu bir **ilişkili
fonksiyondur** — `Nokta` tipiyle ilişkilidir ama belirli bir `Nokta` değeriyle değil.
`boyut` fonksiyonunun imzasında ise ilk parametre `&self`dir; bu parametre çağrının
hangi değer üzerinde yapıldığını belirtir ve çağrı noktasında görünmez, `b.boyut()`
yazımındaki `b` onun yerini alır. Bu, Rust'ın **yöntem** dediği biçimdir.

Ayrım, işin ne yaptığıyla değil imzanın neyi zorunlu kıldığıyla ölçülür: `self` parametresi
varsa çağrı bir değer üzerinden yapılır (yöntem), yoksa tip adı üzerinden yapılır (ilişkili
fonksiyon). Yukarıdaki koşumda `koken()` hiçbir mevcut `Nokta`ya ihtiyaç duymadan sıfırdan
bir değer üretti; `boyut()` ise yalnızca zaten var olan `b` değeri üzerinden çağrılabildi.
İkisi de birer ifadedir — ikisi de bir değer döndürür — ve bu, ifade/deyim/öğe eksenine
yeni bir dal eklemiyor: Rust'ta `()` dönmeyen her fonksiyon çağrısı zaten bir ifadedir,
yöntem olsun ilişkili fonksiyon olsun. Buradaki ayrım eksenin dışındadır — çağrı
sözdizimine, alıcının olup olmamasına aittir.

`boyut` fonksiyonu, noktanın orijine olan uzaklığını iki mutlak değerin toplamıyla
hesaplıyor: `self.x.abs() + self.y.abs()`. Ölçümde `b`, `x=3 y=9` değerini taşıyordu; bu
yüzden `boyut()` çağrısı `3 + 9 = 12` verdi. `koken` ise adından da anlaşılacağı gibi bir
kurucu görevi görüyor: bir `Nokta` değeri üretmenin yalnızca üç yolundan biri değil, sık
kullanılan bir adlandırma alışkanlığıdır — bir tipin en yaygın başlangıç değerini
`Tip::koken()`, `Tip::bos()` ya da `Tip::varsayilan()` gibi bir ilişkili fonksiyonla
sunmak. Bildirim aşamasında bu fonksiyonların kaç tane olacağına dair bir sınır yoktur;
`impl Nokta` bloğu her ikisini de aynı yerde toplar.

Adlandırılmış yapı sözdizimi yalnızca değer kurarken alan adı ister; yöntem çağrısı
sırasında alan adı hiç görünmez. `b.boyut()` yazımında `b`, çağrının hangi değer üzerinde
yapıldığını belirtir, ama `boyut` fonksiyonunun içinde `self.x` ve `self.y` alanlarına
adıyla erişilir. Alıcı, çağrı sözdiziminde tek bir noktaya (`.`) indirgenmiş görünse de,
fonksiyonun gövdesinde alanlarına adıyla ulaşılan tam bir `Nokta` değeridir.

`self` parametresinin önünde tek bir `&` işareti bulunur. Bu işaretin tam anlamı ve
alıcının değeri neden kopyalamadan kullanabildiği, Sahiplik ve Ödünç Alma dersinin
konusudur; burada ölçülen yalnızca alıcının **varlığının** çağrı sözdizimini nasıl
belirlediğidir, alıcının nasıl aktarıldığı değil.

Bir tipin `impl` bloğunda kaç ilişkili fonksiyon ya da yöntem bulunabileceğine dair bir
üst sınır yoktur. `Nokta` gibi küçük bir tip bile birden çok kurucu ilişkili fonksiyona
sahip olabilir — `koken()` yanında `birim() -> Nokta` ya da `ikisi(x: i32, y: i32) ->
Nokta` gibi başka isimlerle başka varsayılan değerler sunulabilir. Hangi isimlerin
kullanılacağı bir dil kuralı değil, bir adlandırma alışkanlığıdır; derleyici için hepsi
aynı sınıfa, ilişkili fonksiyona, girer.

## Alan Sırası Adlandırılmış Yapıda Kimlik Taşımaz

Bir yapı değeri kurarken alanların kaynakta yazılma sırası, bildirimdeki sırayla aynı
olmak zorunda değildir. `Nokta { x: 3, y: 4 }` ile `Nokta { y: 4, x: 3 }` aynı değeri
üretir; derleyici her alanı adına göre eşler, konumuna göre değil.

```rust
// alan_sirasi.rs — adlandirilmis yapida alan sirasi kimlik tasimaz
struct Nokta {
    x: i32,
    y: i32,
}

fn main() {
    let d = Nokta { x: 3, y: 4 };
    let e = Nokta { y: 4, x: 3 };
    println!("{:<18}: x={} y={}", "d (x once)", d.x, d.y);
    println!("{:<18}: x={} y={}", "e (y once)", e.x, e.y);
    println!("{:<18}: {}", "d ve e esit mi", d.x == e.x && d.y == e.y);
}
```

```
d (x once)        : x=3 y=4
e (y once)        : x=3 y=4
d ve e esit mi    : true
```

`d` ve `e` kaynakta farklı sırada yazıldı, ama ikisi de aynı `x` ve `y` değerlerine sahip.
Alan adları burada bir konum belirteci değil, bir eşleştirme anahtarıdır: yazım sırası
okurluk tercihidir, anlamı değiştirmez.

Bu, Rust'ın genel çağrı kuralının dışında kalan bir istisnadır. Bir fonksiyon çağrısında
argümanlar konumla eşlenir — `iki_kat(3)` yazımında `3`ün hangi parametreye gideceği,
parametre listesindeki sırasıyla belirlenir, adıyla değil. Yapı kurma sözdizimi bunun tek
istisnasıdır: `{ }` içindeki her `alan: değer` çifti, `struct` bildirimindeki karşılığını
adından bulur. Bu ayrıcalık yalnızca **kurma** sözdizimine aittir; bir yapı değerinin
alanına erişirken (`a.x` gibi) zaten adla erişilir, orada bir "sıra" sorusu hiç
doğmaz.

**RV2.** — "Sıra anlamı değiştirmiyor" iddiası burada ayrı bir alan karşılaştırma yöntemiyle
değil, `d.x == e.x && d.y == e.y` satırının doğrudan alan alan karşılaştırmasıyla
ölçülüyor; bu satır her iki değerin alanlarının tek tek birbirine eşit olduğunu okur, `d`
ile `e`nin kendisini karşılaştırmaz.

## Demet Yapısında Sıra Tek Kimliktir

Adlandırılmış yapının tam karşıtı demet yapısıdır (tuple struct): alanların adı yoktur,
yalnızca konumu ve tipi vardır. `Renk(u8, u8, u8)` bildirimi üç bayt taşıyan bir tip kurar,
ama bu üç baytın hangisinin "kırmızı" hangisinin "mavi" olduğunu ad değil **konum**
belirler.

```rust
// demet_kimligi.rs — demet yapisinda sira tek kimliktir
struct Renk(u8, u8, u8);

fn main() {
    let kirmizi = Renk(220, 20, 20);
    let Renk(r1, g1, b1) = kirmizi;
    println!("{:<18}: r={} g={} b={}", "Renk(220,20,20)", r1, g1, b1);

    let mavi = Renk(20, 20, 220);
    let Renk(r2, g2, b2) = mavi;
    println!("{:<18}: r={} g={} b={}", "Renk(20,20,220)", r2, g2, b2);
}
```

```
Renk(220,20,20)   : r=220 g=20 b=20
Renk(20,20,220)   : r=20 g=20 b=220
```

Bu **sınırlayıcı ölçümdür**: adlandırılmış yapıda alan sırası serbestken (bir önceki
koşumda `d` ile `e` bunu gösterdi), demet yapısında konum tek kimliktir. `Renk(220, 20,
20)` ile `Renk(20, 20, 220)` aynı üç sayıyı taşımaz — ilkinde ilk konum büyük, ikincisinde
üçüncü konum büyük — ve sonuç iki ayrı renk değeridir. Adlandırılmış yapıda "hangi alan"
sorusunu ad yanıtlar; demet yapısında aynı soruyu yalnızca konum yanıtlar. `Renk(20, 20,
220)` yazımında ilk iki `20`nin hangi alana ait olduğu, o değerin **nerede** durduğuna
bakılarak çözülür.

**RV3.** — Demet yapısında "konum tek kimliktir" iddiası burada aynı üç sayının farklı
konumlara yerleştirilmesiyle, yani `Renk(220, 20, 20)` ile `Renk(20, 20, 220)` çiftinin
üretilmesiyle ölçülüyor: iki çağrı da aynı üç değeri (`20`, `20`, `220`nin bir
permütasyonunu) taşıyor, ama konumları farklı olduğu için sonuçlar da farklı.

Yapısöküm (destructuring) burada da devreye giriyor: `let Renk(r1, g1, b1) = kirmizi;`
satırı, `kirmizi` değerinin üç alanını sırayla `r1`, `g1`, `b1` adlarına bağlıyor. Bu
yazım aslında bir desendir — sağdaki değerin biçimini sol taraftaki adlarla eşler — ve
desenle ayrıştırmanın tam kapsamı sıradaki dersin konusu. Burada yalnızca demet yapısının
alanlarına erişmenin bu yoldan geçtiği görülüyor: adlandırılmış yapıda `a.x` yazılabilirken,
demet yapısında alana adla değil konumla (`renk.0`, `renk.1`, `renk.2`) ya da yapısökümle
erişilir.

Tek alanlı bir demet yapısı, aynı temel tipi taşıyan iki büyüklüğü birbirinden ayırmak
için de kullanılır. `struct Piksel(i32);` ile `struct Milimetre(i32);` ikisi de içeride
bir `i32` taşır, ama derleyici için iki ayrı tiptir; bir `Piksel` değeri, alanı aynı
görünse de, bir `Milimetre` değerinin yerine doğrudan geçmez. Bu, demet yapısının en sık
kullanıldığı biçimdir: mevcut bir tipe yeni bir isim değil, yeni bir **kimlik** kazandırmak.
Adlandırılmış yapıda aynı amaca alan adıyla ulaşılır (`Konum { piksel: i32 }` gibi); demet
yapısı bunu tek bir sarmalayıcı alanla, alan adı hiç yazılmadan yapar.

**RV4.** — Adlandırılmış yapı ile demet yapısı arasındaki karşıtlık, iki ayrı koşumun yan
yana konmasıyla ölçülüyor: `alan_sirasi.rs` sırayı değiştirip sonucun **aynı** kaldığını,
`demet_kimligi.rs` konumu değiştirip sonucun **farklı** olduğunu gösteriyor. İki koşum da
aynı üç girdiyi (üç sayı) kullanıyor; değişen yalnızca tipin adlı mı adsız mı olduğu.

Yapı, Rust'ın veriyi bir arada tutmanın en dolaysız yoludur: sabit sayıda alan, her biri
tek bir tipe bağlı, hepsi aynı anda var. Bu dersin ölçtüğü üç yazım — tam yazım, güncelleme
sözdizimi, ilişkili fonksiyon — hepsi aynı sonuca varır çünkü hepsi aynı sabit alan
kümesini doldurur. Ama her yapı değeri, sabit bir alan kümesine mahkûm değildir; bir
programın modellemesi gereken veri çoğu zaman "ya şu ya bu" biçiminde birden fazla olası
şekle bürünür. Yapı bunu tek başına karşılayamaz — bir `Nokta` her zaman hem `x` hem
`y` taşır, üçüncü bir "hiç taşımıyor" durumu yoktur. Sıradaki ders bu boşluğu dolduran
tipi kuruyor.

## Özet

- `struct` bildirimi bir öğedir: çalıştırıldığında hiçbir değer üretmez, yalnızca bir ad
  tanıtır.
- Bir yapı değeri kurmanın üç yazımı — tam yazım, güncelleme sözdizimi, ilişkili fonksiyon
  — üçü de birer ifadedir ve bir değer üretir.
- Yöntem ile ilişkili fonksiyon arasındaki fark alıcının (`self`) varlığıdır: yöntem bir
  değer üzerinden, ilişkili fonksiyon tip adı üzerinden çağrılır.
- Adlandırılmış yapıda alan sırası anlam taşımaz; alanlar ada göre eşlenir.
- Demet yapısında (tuple struct) alanların adı yoktur, yalnızca konumu vardır; konum tek
  kimliktir ve değiştirildiğinde sonuç değişir.

## Sonraki Adım

Bu ders, bir yapının kaç alan taşıdığını ve bu alanların nasıl kurulduğunu ölçtü — ama bir
yapı değeri her zaman aynı alan kümesini taşır. Sıradaki ders aynı soruyu farklı bir
biçime taşıyor: bir tipin, hangi alanları taşıdığı **duruma göre değişen** birden çok
biçimi olabilir mi? Numaralandırmalar (enum), bir değerin aynı tip altında birden fazla
ayrı durumdan birini taşıyabilmesini kurar; bir sonraki soru bu durumların kaynaktan nasıl
okunduğudur.
