Alıntı (Salih Dinçer):
> Bu uygulamamızda tekrar hafızada yeni bir şey tanımlamak yerine ref kullanarak üzerinde işlem yapılan diziyi göstermeyi yeğledim.
Evet, benim de sonradan yazdığım gibi, o programdaki ref, dilime eleman eklenip çıkarıldığı için gerekliydi. Ama "üzerinde işlem yapılan" diye açıklanabiliyor olması 'ref' kullanımını gerektirmez. Burada ilginç olan, 'ref' kullanımının gerekip gerekmemesi işlemin çeşidine bağlı oluyor. (Bunları zaten biliyoruzdur; yalnızca altını çiziyorum. :))
Örneğin, işlem elemanların değerlerinin iki katlarını almak olduğunda 'ref' olsa da olur olmasa da. Hatta, 'ref' kullanmamak, dilimlerin referans türü karakterleri nedeniyle daha mantıklı görünebilir ve senin "gereksiz şeyleri kullanmamam ve kodları feci derecede kısaltmamla ünlüyümdür" sözüne de daha çok uyar:
void ikiyeKatla(int[] dilim)
{
foreach (ref eleman; dilim) {
eleman *= 2;
}
}
void ikiyeKatla_ref(ref int[] dilim)
{
foreach (ref eleman; dilim) {
eleman *= 2;
}
}
void main()
{
int[] dizi = [ 1 ];
ikiyeKatla(dizi);
ikiyeKatla_ref(dizi);
assert(dizi == [ 4 ]); // <-- ikisi de main'deki elemanları ikiye katlamış
}
foreach'lerdeki 'ref' ise o örnekte zaten her durumda gerekir. Umarım o ref'ler öreği karıştırmıyorlardır. Yoksa aynı örnek foreach'ler şu biçim yazılarak da gösterilebilirdi:
void ikiyeKatla(int[] dilim)
{
foreach (i; 0 .. dilim.length) {
dilim[i] *= 2;
}
}
void ikiyeKatla_ref(ref int[] dilim)
{
foreach (i; 0 .. dilim.length) {
dilim[i] *= 2;
}
}
Hatta for döngüsü de kullanılabilirdi. Sonuçta, öyle bir örnekte dilimleri 'ref' olarak alıp almamanın bir etkisi olmuyor, çünkü işlemler elemanları değiştirmek için kullanılıyorlar.
'ref', eleman eklemek veya çıkartmak gibi dilimin anlamı ile ilgili işlemlerde gerekiyor. (Bunu da Salih'in örneğinde gördük. Parametre 'ref' olmasaydı elemanlar yalnızca işlev içindeki dilim tarafından görülürdü; çünkü o dilim uzadıkça main'deki dilimden farklı elemanlara erişim sağlamaya başlardı.)
Alıntı:
> Başka bir yöntem var mı?
Aslında evet. Başka bir yöntem, Zafer'in de önerdiği gibi sonuç diziyi döndürmek olabilir. Şimdi dilime eleman ekleyen iki işlev yazalım. Birisi 'ref' olarak alıyor ve parametre olarak gelen o dilime ekliyor (Salih'in işlevi gibi), diğeri de yeni bir dilim döndürüyor:
void elemanEkle_ref(ref int[] dilim, size_t adet)
{
foreach (i; 0 .. adet) {
dilim ~= 1;
}
}
int[] elemanEkle(int[] dilim, size_t adet)
{
int[] sonuç = dilim;
foreach (i; 0 .. adet) {
sonuç ~= 1;
}
return sonuç;
}
İkincisi bütün diziyi döndürüyor gibi göründüğü için yavaş diye düşünülebilir ama öyle değildir. Çünkü dilimler perde arkasında bir göstergeden ve bir uzunluktan oluşurlar.
Ama ikincisinin bir tehlikesi var: Bu, yukarıdaki bağlantılarda "paylaşımın sonlanması" ve "belirsizlik" gibi kavramlar olarak geçiyor. 'adet' küçük bir değer olduğunda sonuç ile parametrenin ilk elemanları aynı elemanlar oluyorlar.
Alıntı:
> Tamam, diziyi 'main()' dışında tanımlarsak her yerden (global) ulaşılabilecek ama bu da bana açıkçası çok zarif görünmedi...
Çok kibarsın. ;) Keşke global değişkenlerin tek sorunları zarif olmamaları olsa. :)
Ali
--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]