static foreach
Derleme zamanı foreach
olanağını daha önce Çokuzlular bölümünde görmüştük. O olanak, döngünün derleme zamanında işletilmesini ve kod olarak açılmasını sağlar. Örnek olarak bir çokuzlu üzerinde işletilen aşağıdaki döngüye bakalım:
auto t = tuple(42, "merhaba", 1.5); foreach (i, üye; t) { writefln("%s: %s", i, üye); }
Derleyici döngüyü aşağıdaki eşdeğeri olarak açar:
{ enum size_t i = 0; int üye = t[i]; writefln("%s: %s", i, üye); } { enum size_t i = 1; string üye = t[i]; writefln("%s: %s", i, üye); } { enum size_t i = 2; double üye = t[i]; writefln("%s: %s", i, üye); }
Çok güçlü bir olanak olmasına karşılık, bu olanak her durumda kullanışlı olmayabilir:
- Döngünün her açılımı farklı bir kapsam (ve isim alanı) tanımlar. Bu sayede, yukarıdaki koddaki
i
veüye
gibi değişkenler tanım tekrarı hatalarına neden olmadan kullanılabilirler. Bu bazı durumlarda yararlı olsa da, belirli bir döngü adımında açılan bir kodun başka bir döngü adımında açılan kod tarafından erişilmesini olanaksızlaştırır. - Derleme zamanı
foreach
olanağı yalnızca çokuzlularla kullanılabilir (AliasSeq
olarak erişilebilen şablon parameterleri dahil). Örneğin, aşağıdaki dizi sabit değeri derleme zamanında bilindiği halde,foreach
döngüsünün doğası gereği kod çalışma zamanında işletilir (bazı durumlarda istenen de tam olarak budur):
void main() { enum dizi = [1, 2]; // Derleme zamanında açılmaz, çalışma zamanında işletilir foreach (i; dizi) { // ... } }
- Normal
foreach
gibi, derleme zamanıforeach
döngüsü de yalnızca işlev içlerinde kullanılabilir. Örneğin, modül düzeyinde veya kullanıcı türlerinin içlerinde kullanılamaz.
import std.meta; // Modül düzeyinde işlev yüklemeleri tanımlamaya çalışılıyor: foreach (T; AliasSeq!(int, double)) { // ← derleme HATASI T ikiKatı(T sayı) { return sayı * 2; } } void main() { }
Error: declaration expected, not foreach
break
vecontinue
deyimlerinin derleme zamanıforeach
'inin kendisi ile mi yoksa açılan kodun parçası mı oldukları açık olmayabilir.
static foreach
bu konularda daha fazla seçim sağlayan daha güçlü bir olanaktır:
- Derleme zamanında işletilebilen her çeşit aralıkla kullanılabilir (
1..10
gibi sayı aralıkları dahil). Örneğin, Aralıklar bölümünde gördüğümüzFibonacciSerisi
aralığı ve bir sayının çift olup olmadığını belirleyen bir işlev olduğunu varsayarak:
static foreach (n; FibonacciSerisi().take(10).filter!çift_mi) {
writeln(n);
}
Yukarıdaki döngü aşağıdaki eşdeğeri olarak açılır:
writeln(0); writeln(2); writeln(8); writeln(34);
- Modül düzeyinde kullanılabilir
- Döngünün her adımı için farklı kapsam getirmez. Örneğin, aşağıdaki kod bir işlevin iki yüklemesini modül düzeyinde tanımlamaktadır:
import std.meta; static foreach (T; AliasSeq!(int, double)) { T ikiKatı(T sayı) { return sayı * 2; } } void main() { }
Yukarıdaki döngü aşağıdaki eşdeğeri olarak açılır:
int ikiKatı(int sayı) { return sayı * 2; } double ikiKatı(double sayı) { return sayı * 2; }
static foreach
döngüleri içindekibreak
vecontinue
deyimlerinde etiket belirtilmesi şarttır. Örneğin, birswitch
deyimi içinecase
bölümleri ekleyen aşağıdaki döngüde, açılmakta olan kodun parçası olanbreak
, ilgili olduğuswitch
'i bir etiketle bildirmektedir:
import std.stdio; void main(string[] parametreler) { switchDeyimi: switch (parametreler.length) { static foreach (i; 1..3) { case i: writeln(i); break switchDeyimi; } default: writeln("varsayılan davranış"); break; } }
Yukarıdaki döngü açıldığında bütün switch
deyimi aşağıdakinin eşdeğeridir:
switch (parametreler.length) { case 1: writeln(1); break; case 2: writeln(2); break; default: writeln("varsayılan davranış"); break; }