"Yapı ve Sınıflarda foreach" dersinin son problemi, Okul sınıfının öğrenciler ve öğretmenler için farklı foreach desteği vermesiydi:
http://ddili.org/ders/d/foreach_opapply.html
D.ershane'deki hızımı iyice kaybetmiş olarak o derse eklemek yerine buraya bir çözüm yazıyorum. :)
Tabii program asıl amacından ayrıldı ve üye nitelik eklemeye yardım eden bir de şablon edindi. :) üyeNitelik şablonu, isminin sonuna alt çizgi eklediği 'private' bir üye tanımlıyor ve bu üyeye 'const' erişim sağlayan bir de nitelik işlevi oluşturuyor. Ama asıl konumuz o değil. :)
Okul sınıfının Öğrenci ve Öğretmen'ler için farklı foreach desteği, farklı iki opApply yüklemesiyle sağlanıyor.
Açıklamalar kodun içinde (ve yukarıdaki derste):
import std.stdio;
import std.string;
/*
* Sınıf veya yapı üyesi tanımlamaya yardımcı olan bir şablon
* katması. Belirtilen isimde 'private' bir üye, ve o üyeye 'const' erişim
* sağlayan bir nitelik işlevi tanımlar.
*
* Ürettiği örnek kod:
*
* private dstring isim_;
* public @property dstring isim() const
* {
* return isim_;
* }
*/
template üyeNitelik(Tür, dstring değişken)
{
/*
* Şu anda bir 'şablon katması' (template mixin) tanımlıyoruz. Bu şablon,
* aşağıdaki sınıf tanımlarında 'üyeNitelik!' yazımıyla kullanılacak.
*
* İlginç olarak, bu katma, kendisi bir 'dizgi katması' (string mixin)
* kullanıyor:
*/
mixin (
"private " ~ Tür.stringof ~ " " ~ değişken ~ "_;" ~
"public @property " ~ Tür.stringof ~ " " ~ değişken ~ "() const" ~
"{ " ~
" return " ~ değişken ~ "_;" ~
"}");
/*
* Daha fazla bilgi için:
*
* http://ddili.org/ders/d/katmalar.html
*/
}
class Öğrenci
{
mixin üyeNitelik!(dstring, "isim");
mixin üyeNitelik!(uint, "numara");
this(const dstring isim, uint numara)
{
this.isim_ = isim;
this.numara_ = numara;
}
override string toString() const
{
return format("%s %s", numara, isim);
}
}
class Öğretmen
{
mixin üyeNitelik!(dstring, "isim");
mixin üyeNitelik!(dstring, "ders");
this(const dstring isim, const dstring ders)
{
this.isim_ = isim;
this.ders_ = ders;
}
override string toString() const
{
return format("%s dersine %s öğretmen", ders, isim);
}
}
class Okul
{
private:
Öğrenci[] öğrenciler;
Öğretmen[] öğretmenler;
public:
this(const Öğrenci[] öğrenciler, const Öğretmen[] öğretmenler)
{
this.öğrenciler = öğrenciler.dup;
this.öğretmenler = öğretmenler.dup;
}
/*
* Öğrenci türü için foreach desteği
*
* Kullanıcının yazdığı foreach'in kapsamı, opApply işlecine bir delegate
* olarak gönderilir. foreach'e yazılan parametrenin türü Öğrenci
* olduğunda, burada tanımlanan delegate'in türüne uyar ve bu opApply
* işleci çağrılır.
*
* Daha fazla bilgi için:
*
* http://ddili.org/ders/d/foreach_opapply.html
*/
int opApply(int delegate(ref Öğrenci) işlemler)
{
int sonuç;
/*
* Yapmamız gereken, öğrencileri teker teker kullanıcının delegate'ine
* (ve dolaylı olarak kullanıcının foreach döngüsüne) göndermektir.
*/
foreach (öğrenci; öğrenciler) {
sonuç = işlemler(öğrenci);
/*
* Kullanıcının foreach döngüsü 'break' ile sonlanmış olduğu, ve
* dolayısıyla buradaki döngünün de kırılması gerektiği, 'sonuç'
* değişkeninin sıfırdan farklı bir değer almasından anlaşılır.
*
* Öyle olduğunda bu döngünün de 'break' ile kırılması gerekir.
*/
if (sonuç) {
break;
}
}
/*
* Döngünün nasıl sonlanmış olduğunu bildirmek için 'sonuç'un değeri
* döndürülür.
*/
return sonuç;
}
/**
* Yukarıdakinin benzeri olarak Öğretmen türü için foreach desteği
*/
int opApply(int delegate(ref Öğretmen) işlemler)
{
int sonuç;
foreach (öğretmen; öğretmenler) {
sonuç = işlemler(öğretmen);
if (sonuç) {
break;
}
}
return sonuç;
}
}
void girintiliYazdır(T)(T nesne)
{
writeln(" ", nesne);
}
void main()
{
auto okul = new Okul([ new Öğrenci("Can", 1),
new Öğrenci("Canan", 10),
new Öğrenci("Cem", 42),
new Öğrenci("Cemile", 100) ],
[ new Öğretmen("Nazmiye", "Matematik"),
new Öğretmen("Makbule", "Türkçe") ]);
writeln("Öğrenci döngüsü");
foreach (Öğrenci öğrenci; okul) {
girintiliYazdır(öğrenci);
}
writeln("Öğretmen döngüsü");
foreach (Öğretmen öğretmen; okul) {
girintiliYazdır(öğretmen);
}
}
Ali
--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]