En son BidirectionalRange'e bakmıştım:
http://ddili.org/forum/thread/426
RandomAccessRange olabilmek için dizilerde olduğu gibi indeksle erişim sağlayan opIndex() işlecini tanımlamak gerekir. RandomAccessRange'in tanımı birazcık daha karışık çünkü aslında iki çeşit RandomAccessRange var:
a) opIndex() işlecini de tanımlayan sonsuz bir ForwardRange
veya
b) opIndex() işlecini de tanımlayan bir BidirectionalRange
Hangi çeşit olursa olsun; ayrıca ya aralığın uzunluğunu veren length niteliğinin bulunması, ya da aralığın sonsuz olması gerekiyor (Sonsuz olabilmesi için aşağıda da görüldüğü gibi derleme zamanında tanımlanmış olan bir empty niteliği gerekir.)
Bunlardan birincisinin örneğini vereceğim; çünkü daha önce de kullandığımız SonsuzaKadarSayan zaten sonsuz bir ForwardRange'di. Hatırlayalım:
class SonsuzaKadarSayan
{
int sayaç;
this(int başlangıç = 0)
{
sayaç = başlangıç;
}
static immutable bool empty = false;
@property int front() const
{
return sayaç;
}
void popFront()
{
++sayaç;
}
SonsuzaKadarSayan save() const
{
return new SonsuzaKadarSayan(sayaç);
}
}
Bu sonsuz ForwardRange'imizi RandomAccessRange haline getirmek için opIndex işlecini tanımlayacağız. Ben bunun nasıl yapıldığını şurada anlatmıştım:
http://ddili.org/ders/d/islec_yukleme.html
(Not: İşleç yükleme olanağı o dersi yazdığımdan bu yana genelde değişti ama opIndex konusunda bir fark bulunmuyor. Şimdiki durum Digital Mars'ta şurada:
http://digitalmars.com/d/2.0/operatoroverloading.html#Array
)
opIndex'i tanımlayınca aralığı örneğin 'aralık[ 3 ]' diye kullanabileceğiz ve dizilerde olduğu gibi dördüncü elemanına erişmiş olacağız. (İndeksler 0'dan başladığı için dördüncü eleman diyorum tabii...)
SonsuzaKadarSayan için bunu yapmak acayip kolay: :)
class SonsuzaKadarSayan
{
/* ... */
int opIndex(size_t indeks) const
{
return sayaç + indeks;
}
}
Bütün program:
import std.stdio;
import std.range;
class SonsuzaKadarSayan
{
int sayaç;
this(int başlangıç = 0)
{
sayaç = başlangıç;
}
static immutable bool empty = false;
@property int front() const
{
return sayaç;
}
void popFront()
{
++sayaç;
}
SonsuzaKadarSayan save() const
{
return new SonsuzaKadarSayan(sayaç);
}
int opIndex(size_t indeks) const
{
return sayaç + indeks;
}
}
SonsuzaKadarSayan sonsuzSayaç(int başlangıç = 0)
{
return new SonsuzaKadarSayan(başlangıç);
}
void main()
{
writeln("10'dan başlayarak sonsuza kadar sayan bir ForwardRange");
auto aralık = sonsuzSayaç(10);
writeln("Baştaki eleman: ", aralık.front);
writeln("İndeksi 3 olan eleman: ", aralık[3]);
foreach (i; 0 .. 5) {
aralık.popFront();
}
writeln("Baştan 5 tanesini çıkarttık...");
writeln("Baştaki eleman: ", aralık.front);
writeln("İndeksi 1 olan eleman: ", aralık[1]);
}
Çıktısı:
'10'dan başlayarak sonsuza kadar sayan bir ForwardRange
Baştaki eleman: 10
İndeksi 3 olan eleman: 13
Baştan 5 tanesini çıkarttık...
Baştaki eleman: 15
İndeksi 1 olan eleman: 16
'
İkinci çeşit RandomAccessRange'i de deneyebiliriz ama farklı bir şey yapmayacağız. Tanımı şuydu: opIndex() işlecini de tanımlayan bir BidirectionalRange... Önce bir BidirectionalRange yazsak ve yine opIndex işlecini tanımlasak tamamdır...
Ek soru: :) Dikkat ederseniz baştaki gerekçelerden birisi şöyleydi: Hangi çeşit olursa olsun; ayrıca ya aralığın uzunluğunu veren length niteliğinin bulunması, ya da aralığın sonsuz olması gerekiyor. Hmmm? Nasıl olur da hem BidirectionalRange hem de sonsuz olabilir? BidirectionalRange'in başı da sonu da belldir. Demek ki son tarafı sonsuza doğru uzanamaz. Aklınıza bir şey geliyor mu? :) (Benim geliyor ama emin olamıyorum.)
Devamı gelecek... :)
Ali
--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]
Permalink
Reply