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
constolarak işaretleyin. Böylece o işlevlereimmutabledeğişkenler de gönderilebilir. toStringgibi nesnede değişiklik yapmayan üye işlevleri her zaman içinconstolarak 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.
Kitaplar
Forum
Tanıtım
İletişim
Hakları