const ref
Parametreler ve const
Üye İşlevler
Bu bölümde üye işlevlerin immutable
nesnelerle de kullanılabilmeleri için nasıl const
olarak işaretlenmeleri gerektiğini göreceğiz. Bu bölümde her ne kadar yalnızca yapıları kullanıyor olsak da const
üye işlevler sınıflar için de aynen geçerlidir.
immutable
nesneler
Şimdiye kadarki bazı örneklerde immutable
değişkenler ve nesneler tanımlamış ve immutable
anahtar sözcüğünün nesnelerin değiştirilemez olmalarını sağladığını görmüştük:
immutable okumaSaati = GününSaati(15, 0);
okumaSaati
değiştirilemez:
okumaSaati = GününSaati(16, 0); // ← derleme HATASI okumaSaati.dakika += 10; // ← derleme HATASI
Derleyici immutable
nesneye yeni bir değer atanmasına veya bir üyesinin değiştirilmesine izin vermez. Zaten immutable
olarak işaretlemenin amacı da budur: Bazı nesnelerin değerlerinin değişmemesi program doğruluğu açısından önemli olabilir.
const
olmayan ref
parametreler
Bu kavramı daha önce İşlev Parametreleri bölümünde görmüştük. ref
parametrelerin işlev içinde değiştirilmemeleri yönünde bir kısıtlama yoktur. ref
bir parametresini değiştirmiyor bile olsa, bunun garantisini vermediği için böyle bir işleve immutable
nesne gönderilemez:
// süre'yi değiştirmediği halde const olarak işaretlenmemiş int toplamSaniye(ref Süre süre) { return 60 * süre.dakika; } // ... immutable ısınmaSüresi = Süre(3); toplamSaniye(ısınmaSüresi); // ← derleme HATASI
Derleyici immutable
olan ısınmaSüresi
nesnesinin toplamSaniye
işlevine gönderilmesine izin vermez, çünkü toplamSaniye
işlevi parametresinde değişiklik yapmayacağı garantisini vermemektedir.
const ref
parametreler
const ref
olarak işaretlenen bir parametre, o işlev içinde değiştirilmeyecek demektir:
int toplamSaniye(const ref Süre süre) { return 60 * süre.dakika; } // ... immutable ısınmaSüresi = Süre(3); toplamSaniye(ısınmaSüresi); // ← şimdi derlenir
Parametresini const
olarak işaretleyen işlev o parametrede değişiklik yapmayacağı garantisini vermiş olduğu için işleve immutable
değişkenler de gönderilebilir.
Derleyici const
parametrenin değiştirilmesine izin vermez:
int toplamSaniye(const ref Süre süre) { süre.dakika = 7; // ← derleme HATASI // ... }
const ref
yerine in ref
de kullanılabilir. İlerideki bir bölümde göreceğimiz gibi, in
parametrenin yalnızca giriş bilgisi olarak kullanıldığını ve bu yüzden değiştirilemeyeceğini bildirir:
int toplamSaniye(in ref Süre süre) { // ... }
const
olmayan üye işlevler
Nesneleri değiştirmenin başka bir yolu üye işlevlerdir. Bunu daha önce GününSaati.ekle
işlevinde görmüştük. O üye işlev, üzerinde çağrıldığı nesneyi ona bir Süre
ekleyerek değiştiriyordu:
struct GününSaati { // ... void ekle(Süre süre) { dakika += süre.dakika; saat += dakika / 60; dakika %= 60; saat %= 24; } // ... } // ... auto başlangıç = GününSaati(5, 30); başlangıç.ekle(Süre(30)); // başlangıç değişir
const
üye işlevler
Bazı üye işlevler ise üzerinde çağrıldıkları nesnede değişiklik yapmazlar:
struct GününSaati { // ... string toString() { return format("%02s:%02s", saat, dakika); } // ... }
toString
'in tek işi nesneyi string
olarak ifade etmektir ve zaten o kadar olmalıdır; nesnenin kendisini değiştirmez.
Üye işlevlerin nesnede bir değişiklik yapmayacakları garantisi parametre listesinden sonra yazılan const
sözcüğü ile verilir:
struct GününSaati { // ... string toString() const { return format("%02s:%02s", saat, dakika); } }
O const
, nesnenin o işlev içinde değiştirilmeyeceği anlamına gelir.
Böylece toString
üye işlevi immutable
nesneler üzerinde de çağrılabilir. Aksi halde nesnenin değiştirilmeyeceğinin garantisi bulunmadığından, immutable
nesneler üzerinde çağrılamama gibi yapay bir kısıtlamayla karşı karşıya kalınırdı:
struct GününSaati { // ... // const olarak işaretlenmemiş (yanlış tasarım) string toString() { return format("%02s:%02s", saat, dakika); } } // ... immutable başlangıç = GününSaati(5, 30); writeln(başlangıç); // GününSaati.toString() çağrılmaz!
Çıktısı beklenendiği gibi 05:30
değil, derleyicinin çağırdığı genel bir işlevin çıktısıdır:
immutable(GününSaati)(5, 30)
toString
immutable
bir nesne üzerinde açıkça çağrıldığında ise bir derleme hatası oluşur:
auto dizgiOlarak = başlangıç.toString(); // ← derleme HATASI
Bu açıdan bakıldığında şimdiye kadarki bölümlerde gördüğümüz toString
üye işlevleri yanlış tasarlanmışlardır; aslında onların da const
olarak işaretlenmeleri gerekirdi.
Not: İşlevin nesnede değişiklik yapmayacağını garanti eden const
anahtar sözcüğü aslında işlevin tanımından önce de yazılabilir:
// üsttekiyle aynı anlamda const string toString() { return format("%02s:%02s", saat, dakika); }
Öyle yazıldığında dönüş türüne aitmiş gibi yanlış bir anlam verebildiği için const
anahtar sözcüğünü bu biçimde değil, daha yukarıda gösterildiği gibi parametre listesinden sonra yazmanızı öneririm.
inout
üye işlevler
İşlev Parametreleri bölümünde gördüğümüz gibi, inout
parametrenin değişmezlik bilgisini işlevin çıkış türüne aktarır.
Benzer biçimde, inout
olarak tanımlanmış olan bir üye işlev de nesnenin değişmezlik bilgisini işlevin çıkış türüne aktarır:
import std.stdio; struct Topluluk { int[] elemanlar; inout(int)[] başTarafı(size_t n) inout { return elemanlar[0 .. n]; } } void main() { { // immutable bir Topluluk nesnesi auto topluluk = immutable(Topluluk)([ 1, 2, 3 ]); auto dilim = topluluk.başTarafı(2); writeln(typeof(dilim).stringof); } { // const bir Topluluk nesnesi auto topluluk = const(Topluluk)([ 1, 2, 3 ]); auto dilim = topluluk.başTarafı(2); writeln(typeof(dilim).stringof); } { // Değişebilen bir Topluluk nesnesi auto topluluk = Topluluk([ 1, 2, 3 ]); auto dilim = topluluk.başTarafı(2); writeln(typeof(dilim).stringof); } }
Farklı değişmezliğe sahip üç nesnenin döndürdüğü üç dilim o nesnelerin değişmezliklerine sahiptir:
immutable(int)[] const(int)[] int[]
const
ve immutable
nesneler üzerinde de çağrılabilmeleri gerektiğinden inout
üye işlevler derleyici tarafından const
olarak derlenirler.
Ne zaman kullanmalı
- İşlev içinde değiştirilmeyecek olan parametreleri
const
olarak işaretleyin. Böylece o işlevlereimmutable
değişkenler de gönderilebilir. toString
gibi nesnede değişiklik yapmayan üye işlevleri her zaman içinconst
olarak işaretleyin:struct GününSaati { // ... string toString() const { return format("%02s:%02s", saat, dakika); } }
Böylece yapının ve sınıfın kullanışlılığı gereksizce kısıtlanmamış olur. Bundan sonraki bölümlerdeki kodları buna uygun olarak tasarlayacağız.