2014-05-30 27 views
7

Tôi cần thực hiện một hành động N lần. Cách tốt nhất trong D để làm điều đó là gì?Cách lặp lại câu lệnh N lần (vòng lặp đơn giản)

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

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

có thể có điều gì đó tốt hơn? Lý tưởng nhất là tôi muốn một cái gì đó giống như của Groovy/Ruby times ví dụ:

N.times { 
    action(); 
} 

là nó có thể?

+1

Btw, ví dụ thứ hai của bạn phải sử dụng 'foreach' khá hơn' for' và bạn thực sự có thể loại bỏ 'uint'. Một quy ước được sử dụng trong D cho vòng lặp lặp mà không cần tham chiếu trong vòng lặp là đặt tên cho chúng là '_'. Vì vậy, nó sẽ trở thành 'foreach (_; 0 .. N)' – yaz

+0

Tôi thực sự khuyên bạn nên tải về các tài liệu tham khảo miễn phí và đọc nó. Tất cả điều này được trả lời khá sớm trong cuốn sách. Công trình đầu tiên của bạn. Thứ hai của bạn sẽ là _ trong 0..N {...}. Điều thứ ba là có thể, nhưng tôi không chắc liệu tiện ích mở rộng lần là bình thường hay không. Tôi biết có một ví dụ về chính xác điều đó trong các bài thuyết trình của WWDC, tôi nghĩ là tôi giới thiệu Swift. –

Trả lời

10

Vâng, nó có thể

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");}); 
} 

phiên bản với lập luận ủng hộ:

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:

cho hiệu suất tốt hơn bạn có thể sử dụng bí danh mẫu parametr cho hành động:

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, Cảm ơn bạn :-) Đặc biệt là phiên bản đầu tiên thực sự là đơn giản để làm theo và tôi thích nó. – Parobay

+0

Bạn có thể viết lý do tại sao hiệu suất có thể tốt hơn không? – Parobay

+0

Bởi vì đi qua tên (hành động bí danh) không cần hành động dereferencing. Nhưng tôi không chắc chắn. Và có lẽ có nhiều lý do hơn, do đó, nó sẽ làm cho việc này trở thành một câu hỏi riêng biệt. – Kozzi11

4

Có lẽ một cái gì đó như thế này?

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

Cách sử dụng:

loop(10, {   
    writeln("Hello World!"); 
}); 
Các vấn đề liên quan