Menu
Coddy logo textTech

Generic Struct'lar

Coddy'nin Rust Journey'sinin Object Oriented Programming bölümünün bir parçası — ders 24 / 61.

Şu ana kadar oluşturduğunuz her struct, belirli ve somut türlere sahip alanlara sahipti. Bir Pet, String türünde bir isme; bir Rectangle ise f64 türünde boyutlara sahiptir. Peki ya herhangi bir veri türünü tutabilen bir struct oluşturmak isterseniz?

İşte burada generics devreye girer. Generics, birden fazla türle çalışan esnek ve yeniden kullanılabilir kodlar yazmanıza olanak tanır. Belirli bir türü sabit olarak kodlamak yerine, struct kullandığınızda somut bir türle değiştirilen bir yer tutucu —genellikle T— kullanırsınız.

İşte herhangi bir türü barındırabilen basit bir sarmalayıcı yapı (struct):

struct Wrapper<T> {
    value: T,
}

Struct isminden sonra gelen <T>, genel bir tür parametresi (generic type parameter) tanımlar. Struct içinde T, fiilen kullanacağınız herhangi bir türün yerini tutan bir temsilci görevi görür. Bir örnek (instance) oluşturduğunuzda, Rust somut türü (concrete type) kendisi çıkarır:

let int_wrapper = Wrapper { value: 42 };        // T, i32'dir
let float_wrapper = Wrapper { value: 3.14 };    // T, f64'dür
let text_wrapper = Wrapper { value: "hello" };  // T, &str'dir

Bunların her biri farklı bir somut türdür—Wrapper<i32>, Wrapper<f64> ve Wrapper<&str>—ancak hepsi aynı struct tanımını paylaşır. Bu, temelde aynı şeyi yapan ayrı IntWrapper, FloatWrapper ve StringWrapper struct'ları yazma ihtiyacını ortadan kaldırır.

T harfi sadece bir gelenektir ("Type" kelimesinin kısaltmasıdır). Herhangi bir geçerli tanımlayıcı kullanabilirsiniz, ancak T, Rust'ta ve jenerik içeren diğer çoğu dilde standarttır.

challenge icon

Görev

Kolay

Herhangi bir türde değer tutabilen genel (generic) bir konteyner oluşturalım! Generics (genel türler) özelliğinin kodunuzu nasıl esnek ve yeniden kullanılabilir hale getirdiğini gösteren bir Container yapısı (struct) oluşturacaksınız.

Kodunuzu iki dosya halinde düzenleyeceksiniz:

  • container.rs: T türünde tek bir genel alanı (field) item olan, Container<T> adında genel bir yapı tanımlayın. Bu konteyner herhangi bir türü (tam sayılar, ondalıklı sayılar, dizeler veya başka herhangi bir şey) tutabilmelidir.
  • main.rs: Konteyner modülünüzü dahil edin ve farklı veri türlerini tutan konteynerler oluşturarak esnekliğini gösterin. Üç adet konteyner oluşturacak ve her birinin ne tuttuğunu görüntüleyeceksiniz.

Ana dosyanızda aşağıdaki konteynerleri oluşturun:

  1. Bir tam sayı değeri tutan konteyner (i32 olarak ayrıştırılan ilk girdi)
  2. Bir ondalıklı sayı değeri tutan konteyner (f64 olarak ayrıştırılan ikinci girdi)
  3. Bir dize tutan konteyner (String olarak tutulan üçüncü girdi)

Çıktınız, her bir konteynerin içeriğini şu formatta görüntülemelidir:

Integer container: {value}
Float container: {value}
String container: {value}

Örneğin, 42, 3.14 ve hello girdileriyle:

Integer container: 42
Float container: 3.14
String container: hello

Aynı Container<T> tanımının üç farklı tür için de nasıl çalıştığına dikkat edin; işte generics'in gücü budur!

Üç girdi alacaksınız: bir tam sayı değeri, bir ondalıklı sayı değeri ve bir dize değeri.

Kopya kağıdı

Generikler, bir tür parametresi yer tutucusu kullanarak her türlü veriyi tutabilen struct'lar oluşturmanıza olanak tanır.

Generik bir struct bildirmek için, bir tür parametresi (geleneksel olarak T) ile birlikte açılı ayraçlar kullanın:

struct Wrapper<T> {
    value: T,
}

<T> generik bir tür parametresi bildirir ve struct içindeki T, gerçek tür için bir yer tutucu görevi görür.

Örnekler oluştururken, Rust somut türü çıkarımlar:

let int_wrapper = Wrapper { value: 42 };        // T, i32'dir
let float_wrapper = Wrapper { value: 3.14 };    // T, f64'dür
let text_wrapper = Wrapper { value: "hello" };  // T, &str'dir

Her bir örnek, aynı struct tanımını paylaşırken farklı bir somut tür (Wrapper<i32>, Wrapper<f64>, Wrapper<&str>) haline gelir.

Kendin dene

mod container;

use container::Container;

fn main() {
    // Üç girişi oku
    let mut input1 = String::new();
    std::io::stdin().read_line(&mut input1).expect("Failed to read line");
    let int_value: i32 = input1.trim().parse().expect("Failed to parse integer");

    let mut input2 = String::new();
    std::io::stdin().read_line(&mut input2).expect("Failed to read line");
    let float_value: f64 = input2.trim().parse().expect("Failed to parse float");

    let mut input3 = String::new();
    std::io::stdin().read_line(&mut input3).expect("Failed to read line");
    let string_value = input3.trim().to_string();

    // TODO: Container<T> kullanarak üç konteyner oluşturun
    // 1. int_value tutan bir tam sayı (integer) konteyneri
    // 2. float_value tutan bir ondalıklı sayı (float) konteyneri
    // 3. string_value tutan bir metin (string) konteyneri

    // TODO: Her bir konteynerin içeriğini istenen formatta yazdırın
    // Tam sayı konteyneri: {value}
    // Ondalıklı sayı konteyneri: {value}
    // Metin konteyneri: {value}
}
quiz iconKendini test et

Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.

Object Oriented Programming bölümündeki tüm dersler