Thread overview
Dizileri kırpmak
May 13, 2010

Evet D'de diziler çok güzel. Bunun yanında eşleme tablolarıda çok güzel. Ama diziler hakkında bazı karışıklıklar vardı, bunlar çözüldü mü ?

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

May 13, 2010

Dilimler çok kullanışlı olabiliyor. Komut satırından gelen parametrelerin ilki, yani parametreler[0], her zaman için program başlatılırken kullanılan isimdir.

Aşağıdaki program bütün parametrelerinin toplamını döndürüyor. Dilimlerin sevdiğim tarafı, 'topla' işlevini çağırırken o ilk parametreden kurtulmak için '[1 .. $]' yazmak yetiyor.

import std.stdio;
import std.conv;

int main(string[] parametreler)
{
   if (parametreler.length < 2) {
       writeln("Hiç sayı belirtmediniz");
       return 1;
   }

   writeln("Toplam: ", topla(parametreler[1 .. $]));

   return 0;
}

real topla(string[] veriler)
{
   real toplam = 0L;

   foreach (veri; veriler) {
       toplam += to!real(veri);
   }

   return toplam;
}

Daha da güzeli, o işlem sırasında hiç eleman kopyalanmıyor. topla'ya, asıl dizinin bir dilimi gönderiliyor.

Ali

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

May 13, 2010

Dizilerin gelişimleri durdu ve karışıklıkları çözüldü. (Bunları 2.045 ile aşağıda deniyorum.)

Aklıma gelen iki tanesi:

  1. sabit uzunluklu dizilerin değer türü kabul edilmelerini biz de yaşadık (bu konuyu D.ershane'de değiştirmiştim bile)

Bu, C'den ve C++'dan çok büyük bir fark olarak kabul edilmeli. O dillerde, diziler yarım referans gibi türlerdir. İşlevlere gönderilirken özel kuralları filan vardır.

D'de olay iyice çözülmüş durumda: sabit uzunluklu diziler kopyalanır, dinamik diziler (aslında dilim ile aynı şey) ise referans türüdür; kopyalanmaz:

// Sabit uzunluklu dizi olduğu için, parametre kopyalanır
void sabitAlan(int[3] dizi)
{
   // yalnızca yerel 'dizi' değişir
   dizi[2] = 22222;
}

// Dilim olduğu için, parametre kopyalanmaz
void dilimAlan(int[] dizi)
{
   // gönderilen asıl dizi değişir
   dizi[2] = 22222;
}

void main()
{
   int[3] sabitUzunluklu = [ 0, 1, 2 ];
   sabitAlan(sabitUzunluklu);
   // değişmemiş; çünkü kopyalanarak gönderilir
   assert(sabitUzunluklu == [ 0, 1, 2 ]);

   int[] dilim = [ 0, 1, 2 ];
   dilimAlan(dilim);
   // değişmiş; çünkü referans olarak gönderilir
   assert(dilim == [ 0, 1, 22222 ]);

   // Sabit uzunluklu olan da dilim olarak gönderilebilir
   dilimAlan(sabitUzunluklu);
   assert(sabitUzunluklu == [ 0, 1, 22222] );
}
  1. Dilimlere eklemek, şaşırtıcı sonuçlar doğurabilir:
void main()
{
   // İki tane elemanı olan bir dilim oluşturuyoruz
   int[] dilim;
   dilim ~= 3;
   dilim ~= 33;

   // İçinde 3 ve 33 bulunmasını bekleriz
   assert(      dilim == [ 3, 33 ]);

   // Başka bir dilimi, bu dilim ile ilkliyoruz
   int[] başka_dilim = dilim;

   // Bu noktadan sonra iki dilimin elemanları da aynıdır
   // (aslında "aynı elemanlara erişim sağlarlar" demek daha
   // doğru)
   assert(      dilim == [ 3, 33 ]);
   assert(başka_dilim == [ 3, 33 ]);

   // Buradaki 'is' işleci, "aynı elemanlara erişim sağlar"
   // anlamına geliyor
   assert(dilim is başka_dilim);

   // Göstergeler dersinde gördüğümüz .ptr değerleri de aynı
   assert(dilim.ptr == başka_dilim.ptr);

   // Birinci dilimde bir değer değiştiriyoruz
   dilim[0] = 7;

   // Evet, ikisinin de ilk elemanları değişmiştir
   assert(      dilim == [ 7, 33 ]);
   assert(başka_dilim == [ 7, 33 ]);

   // Diğer ilişkilerinde bir değişme beklemeyiz; aynılar
   assert(dilim is başka_dilim);
   assert(dilim.ptr == başka_dilim.ptr);

   // Dilimlerden birisine bir eleman ekliyoruz
   dilim ~= 333;

   // O dilimin yeni bir elemanı oluyor
   assert(      dilim == [ 7, 33, 333 ]);

   // Diğer dilimin bu konuyla bir ilgisi yok
   assert(başka_dilim == [ 7, 33 ]);

   // Artık "aynı elemanlara erişim sağlar" diyemeyiz; o
   // yüzden, !is işleci doğru oluyor
   assert(dilim !is başka_dilim);

   // İşin garibi, erişim sağladıkları elemanlar yine de
   // "aynı", çünkü .ptr değerleri aynı
   assert(dilim.ptr == başka_dilim.ptr);

   // Yine değer değiştiriyoruz
   dilim[0] = 8;

   // O değişikliği ikisinde de görüyoruz
   assert(      dilim == [ 8, 33, 333 ]);
   assert(başka_dilim == [ 8, 33 ]);

   //  İşler bu noktadan sonra ilginçleşiyor
   //
   // Önce, bu aşamada belleğin nasıl olduğuna
   // bakalım. Ortalıkta yalnızca 3 tane eleman var. dilim,
   // bunların üçüne de erişim sağlıyor; başka_dilim ise ilk
   // ikisine:
   //
   //      ... |  8  |  33 | 333 | ...
   //             \      \    \
   //               -------------- dilim
   //               \      \
   //                 ---------- başka_dilim

   // Şimdi, "diğer" dilime eleman ekliyoruz
   başka_dilim ~= 3333;

   // O son işlem, bu iki dilimin arasındaki "paylaşma"
   // ilişkisini sona erdirir. Bunun nedeni, ikinci dilimin
   // sonunda serbestçe eleman ekleyeceği yer
   // bulunmamasıdır. Çünkü orada birinci elemanın eklemiş
   // olduğu 333 vardır.
   //
   // Önemli nokta: O son işlem, başka_dilim'in elemanlarının
   // yeni bir yere kopyalanmalarına ve başka_dilim'in artık
   // farklı elemanlara erişim sağlamasına neden olur:
   //
   //      ... |  8  |  33 | 333 | ...
   //             \      \    \
   //               -------------- dilim
   //
   //
   //      ... |  8  |  33 | 3333 | ...
   //               \      \   \
   //                 ------------- başka_dilim

   // Evet, içerikler beklediğimiz gibi:
   assert(      dilim == [ 8, 33, 333 ]);
   assert(başka_dilim == [ 8, 33, 3333]);

   // Artık farklı elemanlara erişim sağlıyorlar (yani !is)
   assert(dilim !is başka_dilim);

   // Kopyalandıklarını da .ptr değerlerinin farklı
   // olmasından anlıyoruz
   assert(dilim.ptr != başka_dilim.ptr);
}

Çok uzun bir hikaye oldu. :)

Aslında hiç de zor bir konu değil ama dilimlerin belirli bir noktadan sonra birbirlerinden bağımsız hale gelebileceklerini anlamamız gerekiyor.

Ali

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]