Merhaba,
>Üst Not: Ali hocam işin içinden çıkamadığım modüller arası alan ve kapsam ile ilgili bir sorum (burda bulamadım) var. Sorum aşağıda, yazdıklarımın sonundaki cümleye çözüm var mı?
Az önce Phobos kütüphanesinin aralıklarla ilgili olanaklarına şöyle bir bakıyordum ve şu tanıdık kodlara (ve tabi daha nicesine!) rastladım:
@property bool empty(T)(auto ref scope T a)
if (is(typeof(a.length) : size_t))
{
return !a.length;
}
/// ...
@property ref inout(T) front(T)(return scope inout(T)[] a) @safe pure nothrow @nogc
if (!isAutodecodableString!(T[]) && !is(T[] == void[]))
{
assert(a.length, "Attempting to fetch the front of an empty array of " ~ T.stringof);
return a[0];
}
/// ...
void popFront(T)(scope ref inout(T)[] a) @safe pure nothrow @nogc
if (!isAutodecodableString!(T[]) && !is(T[] == void[]))
{
assert(a.length, "Attempting to popFront() past the end of an array of " ~ T.stringof);
a = a[1 .. $];
}
Örneğin popFront() tam olarak şurada:
https://github.com/dlang/phobos/blob/master/std/range/primitives.d#L2288
Aslında bunları kullanıyordum ve hatta belki de farkında olmadan kullanıyoruz bile! Yani en basitten biz diziyi foreach()
ile ekrana yazdırdığımızda (zaten ilk cümlede ifade edilmiş) bunlar çağrılıyor. Gerçi kendi türlerimizde bu 3 işlevi (örn. bir yapı içerisinde) tanımlayıp Andrei'nin hep savunduğu aralıklar dünyasına girebilirsiniz...
Bu konular için lütfen okuyunuz: Ali Çehreli çevirisi şu yazı: https://ddili.org/makale/eleman_erisimi_uzerine.html ya da orinali için: https://www.informit.com/articles/printerfriendly/1407357
Neyse, ana konumuza dönelim: Özelleştirme!
Peki şimdi olaya sadeleştirme gözüyle bakarsak üçünü daha basit şekilde şöyle de yazabirdik:
class Foo
{
bool isFull(T)(auto ref scope T a)
{
return a.length > 0;
}
@safe pure nothrow @nogc
{
ref inout(T) frontItem(T)(return scope inout(T)[] a)
{
return a[0];
}
void nextItem(T)(scope ref inout(T)[] a)
{
a = a[2 .. $]; // aslında, dilimin ilk değeri 1 olmalı (geçici)
}
}
}
> Not: Lütfen class Foo
'ya takılmayın, çünkü artık aynı isimde yeni 3 işlevimiz var. Onun orijinalleri class Orijinal_Kodlar
içine de alabilirsiniz. Ben sadece aralarında geçiş yapmak için kolaylık olsun diye koydum.
Şimdi bunları kullanacak örneğimize geçelim. Ama dikkat (!) empty()
'i hemen oracakta ismini değiştirerek ve değilini kaldırarak özelleştirdim. Böylece while()
içinde ikinci kez tersini almamış oldum:
import std.stdio;
void main()
{
int[] sayılar = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
//with(new Orijinal_Kodlar) /*
with(new Foo)//*/
{
while(isFull(sayılar))
{
frontItem(sayılar).write(" "); // 1 3 5 7 9
nextItem(sayılar);
}
}
writeln("(tek sayılar)");
}
Yukardaki örneği çalıştırmak gereksiz çünkü orijinal kodlar ile dizideki 10 sayıyı ekrana yazdırıyoruz. Farklı olan, Foo'daki değişitirilmiş kodlarda. Yani geçici olarak popFront()
içinde dilimi 2'den başlattım. Dolayısıyla tek sayılar ekrana yazacak hepsi bu.
Bütün bunları kendi kütüphanenizde kullanabilirsiniz. Örneğin ben isFull'ü bir sınıf veya yapı içine aldığımda main()
içinde şu şekilde kullanamıyorum:
bool doluMu(T)(auto ref scope T a) {
return a.length > 0;
}
/// ...
while(sayılar.doluMu)
Eğer doluMu() modüller arası alanda (örneğin tek dosyalı bir uygulamada main() dışında) olursa elbette şu hatayı almayacaksınız:
>Error: no property doluMu
for type int[]
Ali hocam bu konuyu şöyle dile getirmiş (genel olarak):
>İsim Alanı
D'de her isim, tanımlandığı noktadan başlayarak hem içinde tanımlandığı kapsamda, hem de o kapsamın içindeki kapsamlarda geçerlidir. Her kapsam bir isim alanı tanımlar.
İçinde tanımlandığı kapsamdan çıkıldığında, isim artık geçersiz hale gelir ve derleyici tarafından tanınmaz [...]
Yani işlevler/yapılar içinde elbette bir kapsam var, bu doğal. Ama UFCS'yi kullanmak istediğimizde kapsamın içinde olsa dahi sorun yaşabiliriz. Bunun olmaması için konu başından beri bahsettiğim InputRange işlevlerini kendi modülüm (sdb.range
) içine alırsam hiç bir sorun yaşamam:
import sdb.range;
void main()
{
int[] tekler, rakamlar = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ];
bool doluMu(T)(auto ref scope T a) {
return a.length > 0;
}
/* işlev main() içinde olduğu için zaten çalışmaz!
"rakamlar[] dolu mu? ".write;
if(rakamlar.doluMu() ) {
"Evet, dolu!".writeln;
} else {
"Hayır, boş!".writeln;
}//*/
auto test = rakamlar; // rakamlar tükenmesin diye, o bize lazım :)
while(test.isFull)
{
const r = test.frontItem;
if(r % 2) tekler ~= r;
test.nextItem;
}
import std.algorithm : all;
assert(tekler.all!"a % 2"); // tamamı tek sayı, kanıtlandı...
assert(
!all!"a % 2"(rakamlar)
); // iddia ediyorum içinde sadece tek sayı yoktur!
}
Neyse, bu dersi bir şeyler öğrenmek için ve bizzat deneyerek uyguladım. Siz de buradan veya başka bir bölümden başlayarak aralıklar konusunda derinlemesine bilgi sahibi olabilirsiniz. Bir tek "no property" hatasını çözemiyorum!
Ali hocam, işlevi parantezi ile birlikte kullanmak istemesek ve evet, bir nesnenin üyesi/özelliği olmadığını biliyoruz ama UFCS gereği çalışması gerekmez mi? Yani illa ki modüller arası bir alanda olmalı ha!
Teşekkürler...