2014-05-30 12 views
7

Ich muss eine Aktion N-mal ausführen. Was ist der beste Weg in D?Wie wiederhole ich eine Anweisung N-mal (einfache Schleife)

for(uint i=0; i<N; i++) 
    action(); 

foreach(uint i; 0.. N) 
    action(); 

vielleicht etwas besseres? Im Idealfall würde ich times z

N.times { 
    action(); 
} 

ist das so etwas wie Groovy/Rubin will es möglich?

+1

Btw, Ihr zweites Beispiel muss 'verwenden foreach' anstatt' for' und man kann tatsächlich entfernen 'uint'. Eine Konvention, die in D für Loop-Iteratoren verwendet wird, die in der Schleife nicht referenziert werden müssen, ist, sie '_' zu nennen. So wird es 'foreach (_; 0 .. N)' – yaz

+0

Ich würde wirklich empfehlen, die freie Referenz herunterzuladen und sie zu lesen. All dies wird in dem Buch ziemlich früh beantwortet. Deine ersten Arbeiten. Deine zweite wäre für _ in 0..N {...}. Die dritte ist möglich, aber ich bin mir nicht sicher, ob die Zeitverlängerung normal ist. Ich weiß, dass es ein Beispiel für genau das in den WWDC-Präsentationen gibt, denke ich. –

Antwort

10

Ja, es möglich ist,

import std.stdio; 
import std.traits; 

void foo() 
{ 
    writeln("Do It!"); 
} 

void times(T,N)(N n, T action) if (isCallable!T && isIntegral!N) 
{ 
    static if (ParameterTypeTuple!action.length == 1 
      && isIntegral!(ParameterTypeTuple!action[0])) 
     foreach (i; 0 .. n) 
      action(i); 
    else 
     foreach (i; 0 .. n) 
      action(); 
} 

void main(string[] args) 
{ 
    10.times(&foo); 
    10.times({writeln("Do It!");}); 
    10.times((uint n){writeln(n + 1, " Round");}); 
} 

Version mit Argumenten unterstützen:

import std.stdio; 
import std.traits; 

void foo() 
{ 
    writeln("Do It!"); 
} 

struct Step { 
    alias n this; 
    size_t n; 
    this(size_t i) 
    { 
     n = i + 1; 
    } 
} 

struct Index { 
    alias n this; 
    size_t n; 
} 

void times(T,N,A...)(N n, T action, A args) if (isCallable!T && isIntegral!N) 
{ 
    alias PTTAction = ParameterTypeTuple!action; 
    static if (PTTAction.length >= 1) 
    { 
     alias FP = PTTAction[0]; 
     static if (is(Index == FP) || is(Step == FP)) 
      foreach (i; 0 .. n) 
       action(FP(i), args); 
     else 
      action(args); 
    } 
    else 
     foreach (i; 0 .. n) 
      action(); 
} 

void main(string[] args) 
{ 
    10.times(&foo); 
    10.times({writeln("Do It!");}); 
    10.times((Step n){writeln(n, " Step");}); 
    10.times((Index n, string msg){writeln(n, msg);}, " Index"); 
    stdin.readln; 
} 

UPDATE:

für eine bessere Leistung können Sie alias Vorlage parametr für Aktion verwenden:

void times(alias action,N)(N n) if (isCallable!action && isIntegral!N) 
{ 
    static if (ParameterTypeTuple!action.length == 1 
      && isIntegral!(ParameterTypeTuple!action[0])) 
     foreach (i; 0 .. n) 
      action(i); 
    else 
     foreach (i; 0 .. n) 
      action(); 
} 

void main(string[] args) 
{ 
    10.times!(foo); 
    10.times!({writeln("Do It!");}); 
    10.times!((uint n){writeln(n + 1, " Round");}); 
} 
+0

OK, Danke :-) Besonders die erste Version ist wirklich einfach zu folgen und ich liebe sie. – Parobay

+0

Können Sie schreiben, warum die Leistung besser sein könnte? – Parobay

+0

Da die Übergabe nach Namen (Alias-Aktion) keine Dereferenzierungsaktion erfordert. Aber ich bin mir nicht sicher. Und vielleicht gibt es mehr Gründe, also wäre es interresing, dies eine separate Frage zu machen. – Kozzi11

4

Vielleicht so etwas?

void loop(int n, void delegate() func) 
{ 
    foreach (i; 0 .. n) 
    { 
     func(); 
    } 
} 

Verbrauch:

loop(10, {   
    writeln("Hello World!"); 
});