Alıntı (zafer):
> Gerçekten projeler ögrenim için kesinlikle şart, bu iş sadece okuyarak olmuyor, olayın içine girip yaşamak gerekiyor.
Kesinlikle! Bu kadar çok ve güzel konuyu açtığın için gerçekten çok teşekkürler. Öğreniyoruz ve pekiştiriyoruz.
Alıntı:
> kodda foreach döngüsüne i sayaç değişkenini eklediğimde "Segmentation fault" hatası alıyorum. İlgili kod aşağıda,
> private void SoruListesiHazirla()
> {
> File dosya = File(_soruDosyasi, "rb");
>
> foreach (i, satir; dosya.byLine())
> {
> string[] soru = cast(string[])split(satir, ":");
>
> //_soruListesi.length = i + 1;
> //_soruListesi[i] = Soru(soru[0], soru[1]);
> }
> }
> ```
>
> Sorun ne olabilir?
>
Aynısını dün ben de yaşamış ve konuyu uzatmamak için yazmamıştım. ;)
Bu sayaç konusu İngilizce forumlarda da tartışılmıştı. Derleyicinin bu desteği her tür için otomatik olarak vermesinin iyi olacağı savunulmuştu. Ne yazık ki çeşitli nedenlerle olmadı.
Burada foreach ile kullanılan tür, std.stdio.File.ByLine (byLine() işlevi tembel bir ByLine döndürür.) Bir tür olan ByLine, foreach ile nasıl işleyeceğini kendisi belirlediği için, sayaç sunup sunmayacağı ona kalmış oluyor.
Kısa yanıt: ByLine'ın belgeleri sayaç kullanımı göstermediği için onu sayaçla kullanamıyoruz.
Uzun yanıt: ByLine'ın tanımına baktığımda foreach desteğini opApply() ile değil; empty(), front(), ve popFront() aralık işlevleri ile sağladığını görüyorum. Zaten aralık işlevleri kullanıldığında foreach için yükleme sağlanamıyor. Tek yapabildiğimiz, foreach'te tek değişken kullanmak.
Bütün bunlara bakınca, aslında foreach'in bu durumda iki değişkenle kullanılmasının yasal olmaması gerektiğini görüyorum. Derleyici izin vermemeliydi.
Evet, bilinen bir hataymış:
http://d.puremagic.com/issues/show_bug.cgi?id=6723
dmd'nin git'teki son halinde de galiba çözülmüş:
https://github.com/D-Programming-Language/dmd/commit/569077b
Kısacası, lütfen bir sonraki sürümü bekleyiniz. :)
Keşke daha hoş olabilseydi ama en basit çözüm, kendi sayaç'ımızı tanımlamak:
int sayaç;
foreach (satır; dosya.byLine()) {
writefln("%s: %s", sayaç, satır);
++sayaç;
}
Şimdi, her ne kadar son derece okunaksız olsa da bu işin aralıklarla da yapılabileceğini göstermek istiyorum:
import std.stdio;
import std.range;
void main()
{
auto dosya = File("deneme.txt");
foreach (sayaç_ve_satır; zip(iota(int.max), dosya.byLine())) {
writefln("%s: %s", sayaç_ve_satır[0], sayaç_ve_satır[1]);
}
}
iota, kendisine verilen değere kadar teker teker sayar. zip ise kendisine verilen belirsiz sayıdaki aralığı aynı miktarda adım adım ilerletir. Sonuçta iota sayar, ByLine satır satır ilerler.
zip'in değeri, kendisine verilen aralıkların elemanlarından oluşan bir çokuzludur (tuple). O çokuzlu değerin 0 numaralı elemanı iota'ya, 1 numaralı elemanı da ByLine'a karşılık geliyor.
Çokuzlular bölümü:
http://ddili.org/ders/d/cokuzlular.html
Tabii bence yukarıdaki zip'li çözüm oldukça okunaksız. Acaba iota'nın görevini kendi içine gizleyen bir aralık tanımlasak nasıl olur:
import std.stdio;
import std.range;
/*
-
Bu aralık herhangi bir InputRange aralığı ile işleyebilir. Bu aralığın
-
elemanları, aşağıdaki Sayaçla.Eleman türünden oluşurlar.
*/
struct Sayaçla(Aralık)
if (isInputRange!Aralık)
{
size_t sayaç;
Aralık aralık; // asıl aralık
Eleman baştaki; // front()'tan döndüreceğimiz elemanımız
// Bu aralığın elemanları iki parçadan oluşur
struct Eleman
{
size_t sayaç;
ElementType!Aralık eleman;
}
// Aralık boş kabul edildiğinde varsayılan bir Eleman döndürüyoruz (zaten
// kullanıcılar aralığımız boş olduğunda bizi çağırmamalıdırlar); yoksa
// geçerli bir sayaçtan ve asıl elemandan oluşturuyoruz.
void baştakiniKur()
{
baştaki = (empty
? Eleman()
: Eleman(sayaç, aralık.front()));
}
this(Aralık aralık)
{
this.sayaç = 0;
this.aralık = aralık;
baştakiniKur();
}
@property bool empty() const
{
return aralık.empty;
}
Eleman front()
{
return baştaki;
}
void popFront()
{
++sayaç;
aralık.popFront();
baştakiniKur();
}
}
// Hemen hemen bütün yapı ve sınıf şablonunda olduğu gibi bir kolaylık işlevi
Sayaçla!Aralık sayaçla(Aralık)(Aralık aralık)
{
return Sayaçla!Aralık(aralık);
}
void main()
{
auto dosya = File("deneme.txt");
foreach (i; sayaçla(dosya.byLine())) {
writefln("%s: %s", i.sayaç, i.eleman);
}
}
Ali
--
[ Bu gönderi, <http://ddili.org/forum>'dan dönüştürülmüştür. ]