Herkese selam...
Geçen ay yabancı forumda (-bknz. number ranges) iota'yı emekliye ayırabilecek harika bir aralık veren yapımız olmuştu; Ali hoca sayesinde...
Baktım da aradan tam 1 ay geçmiş ve tam unutmadan üzerinden geçelim derim. Haddim olmayarak 1-2 öneride bulunacağım çünkü orijinal iota(3)
ile 0'dan 2'ye kadar aralık döndürebiliyormuş. Bizimkisi parametre serbestliği olmadığı için bunu yapamıyor.
Hadi, aşama aşama başlayalım:
/***********************************************/
/*** ***/
/*** Inclusive Range ***/
/*** for D v2 ***/
/*** ***/
/*** 21 January 2022 by Ali Çehreli ***/
/*** ***/
/***********************************************/
struct InclusiveRange(T) {
private:
T first, last;
bool empty_;
public T step; // SDB@79 ekledi
this(U)(in U first,
in U last,
in U step) // SDB@79 ekledi
in (first <= last, format!"\n
Invalid range:[%s,%s]."(first, last))
{
this.first = first;
this.last = last;
this.step = step; // SDB@79 ekledi
this.empty_ = false;
}
Şimdi 2 konu kesin:
-
Ondalıklı sayılarda malum yuvarlama sorunları nedeniyle float, double, real türlerde kullanmayacağız/hata döndürebiliriz.
-
Ayrıca retro() imkanı varken yapıyı ekstradan olanaklar (BidirectionalRange) için genişletmeye gerek yok.
Aslında 3. parametre olan step de kesin çünkü Inclusive Range olarak anılabilmesi için bunun olmaması gerekiyor. Olursa bazı testlerden geçemiyor çünkü tam sınırlarda geziniyoruz. Yani sayıların üstünden atlayan atımız (pointer, gösterge) uçurum kenarında. Malum T.max'a ulaşınca yuvarlanıyoruz ama ben her şeye rağmen kullanıyorum o yüzden yukarda orijinal kodda olmayan kısımları SDB@79 ile imledim.
Peki şunlara (aşağıdaki kolaylık işlevidir) itirazım yok değil mi?
-
inclusiveRange(0, 1); => [ 0, 1 ]
(Bunu iota'dan beklemiyoruz çünkü inclusive (kapsayan) özelliğini içermiyor.) -
inclusiveRange(1, 1); => [ 1 ]
-
inclusiveRange(1, 0); => Exception!
İşte bu son durumu lezzetli bir şekilde, this() içinde ve sözleşmeli programlama marifetiyle (yukardaki kodlarda) hata attıyoruz. Bence gerek yok çünkü retro() kullanıyoruz ve tersten sıralanmış bir aralık istemiyoruz. O zaman önerim şu:
Exception atmasın diye o satırları kaldıralım ve yerine kolaylık işlevi içine yeni bir if() satırı ekleyelim:
if(last < first) return InclusiveRange!T(last, first, step);
Yetmez, hem parametre serbestliğini kullanalım hem de tür çıkarımı (inference) için de varsayılan bir tür seçelim, örneğin (T = int)
olsun. Özetle şu örnekler böyle sonuçlanıyor:
-
inclusiveRange(1, 0); => [ 0, 1 ]
-
inclusiveRange(10); => [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
-
inclusiveRange(); => [ ]
Ancak istenmeyen bir durum var; o da yukardaki 3. örneğin boş dönse de length = 1 olması. İşte bunu nasıl çözerim bilmiyorum. Kod şöyle:
/* 19 Şubat Parametre Serbestliği Genişletildi */
auto inclusiveRange(T = int) (T f = cast(T)0,
T l = cast(T)0,
T s = cast(T)0) {
static assert (!isBoolean!T, "\n
Cannot be used with bool type\n");
if (!s) s++;
if (l < f) {
return InclusiveRange!T (l, f, s);
} else if (f == 0 && l == 0) {
auto boşAralık = InclusiveRange!T (f, l, s);
boşAralık.empty_ = true;
return boşAralık;
}
return InclusiveRange!T (f, l, s);
}