38用d編程條件編譯

-unittest單元測試.
in,out,invariant沒有-release.
單元測試/合同用於程序正確性.
模板只特化實際使用類型.

void swap(T)(ref T lhs, ref T rhs) {
    T temp = lhs;
    lhs = rhs;
    rhs = temp;
}

unittest {
    auto a = 'x';
    auto b = 'y';
    swap(a, b);

    assert(a == 'y');
    assert(b == 'x');
}

void swap(T : uint)(ref T lhs, ref T rhs) {
    lhs ^= rhs;
    rhs ^= lhs;
    lhs ^= rh;  // TYPO!
}

void main() {
}

原來認爲^臨時的慢.但相反,現代微控器這種方法更慢.

unittest {
    uint i = 42;
    uint j = 7;
    swap(i, j);

    assert(i == 7);
    assert(j == 42);
}

//單元測試,發現錯誤
d的條件編譯:
debug
version
static if,c++已有
is expression
__traits
開發期間,-調試很有用.

debug a_conditionally_compiled_expression;

debug {
    // ... 條件編譯代碼...

} else {
    // ... 否則編譯代碼 ...
}

調試

size_t binarySearch(const int[] values, in int value) {
    writefln("searching %s among %s", value, values);

    if (values.length == 0) {
        writefln("找不到%s", value);
        return size_t.max;
    }

    immutable midPoint = values.length / 2;

    writefln("考慮%s索引", midPoint);

    if (value == values[midPoint]) {
        writefln("found %s at index %s", value, midPoint);
        return midPoint;

    } else if (value < values[midPoint]) {
        writefln("必在前半");
        return binarySearch(values[0 .. midPoint], value);

    } else {
        writefln("必在後半");
        return binarySearch(values[midPoint + 1 .. $], value);
    }
}

在前面加上debug,這樣下次還可用.
debug writefln("%s not found", value);
dmd deneme.d -ofdeneme -w -debug就可搞定了
只輸出我想要的:

debug(binarySearch) writefln("%s not found", value);

dmd deneme.d -ofdeneme -w -debug=binarySearch
這樣只調試這種塊.
塊也可以

    debug(binarySearch) {
        // ...
    }

dmd deneme.d -w -debug=binarySearch -debug=stackContainer
多個調試塊.
可以逐漸增加調試級:

debug import std.stdio;

void myFunction(string fileName, int[] values) {
    debug(1) writeln("entered myFunction");
//1級.

    debug(2) {//2級
        writeln("the arguments:");
        writeln("  file name: ", fileName);

        foreach (i, value; values) {
            writefln("  %4s: %s", i, value);
        }
    }

    // ...實現函數...
}

void main() {
    myFunction("deneme.txt", [ 10, 4, 100 ]);
}
//---
$ dmd deneme.d -w -debug=1
$ ./deneme 
entered myFunction

將打印級數小的,級越大,越詳細
version(tag) 和 version(level),類似debug.

  version(testRelease) /* ... an expression ... */;

    version(schoolRelease) {
        //此版本與學校發佈相關
    } else {
        // ... 否則編譯代碼...
    }

    version(1) aVariable = 5;

    version(2) {
        // ... 2版本特徵 ...
    }

$ dmd deneme.d -w -version=record -version=precise_calculation定義多個版本
完整預定義版本標誌
none(禁用),all(允許)代碼塊.

version(Windows) {
    immutable newline = "\r\n";
} else version(Posix) {
    immutable newline = "\n";
} else {
    static assert(0, "不支持 OS");
}

用於確定系統的換行符.

import std.stdio;

debug(everything) {
    debug = binarySearch;
    debug = stackContainer;
    version = testRelease;
    version = schoolRelease;
}

void main() {
    debug(binarySearch) writeln("binarySearch is active");
    debug(stackContainer) writeln("stackContainer is active");

    version(testRelease) writeln("testRelease is active");
    version(schoolRelease) writeln("schoolRelease is active");
}

這些debugversion變量就像個一樣,加進去.只要有其中一個,就可以調試了.就像調試集/版本集.
命令如下dmd deneme.d -w -debug=everything.
static if,編譯時條件判斷,只要是編譯時已知的東西都可以用它.用來決定如何生成代碼.邏輯表達式經常可以利用is雙下劃線trait.
可在模塊域類,構,模板中出現static if.也可以有if語句.
簡單例子:

import std.stdio;

struct MyType(T) {
    static if (is (T == float)) {
        alias ResultType = double;

    } else static if (is (T == double)) {
        alias ResultType = real;

    } else {//
        static assert(false, T.stringof ~ " is not supported");
    }

    ResultType doWork() {
        writefln("The return type for %s is %s.",
                 T.stringof, ResultType.stringof);
        ResultType result;
        // ...
        return result;
    }
}

void main() {
    auto f = MyType!float();
    f.doWork();

    auto d = MyType!double();
    d.doWork();
}

只能用於雙精,返回類型取決於其中一個.
注意,編譯時的比較都必須寫static if.如果不寫static,將把剩下的if塊插入進去.就與本意不一樣了.
static assert,編譯時斷定是否滿足條件.如爲假,程序直接退出.可出現在程序的任何中.
如上面程序,auto i = MyType!int();,將會導致static assert "int is not supported".不支持.
如算法只適用於特定情況:

T myAlgorithm(T)(T value) {
    static assert((T.sizeof % 4) == 0);
    //要求T的大小是4的整數倍
    // ...
}

調用時,如果爲char,就會失敗.
這樣,避免使用錯誤的類型,而產生可能的錯誤了.
__traits提供編譯時類型和表達式的信息.
編譯器收集的.可以這樣__traits(keyword, parameters)
關鍵詞爲要查的信息,參數爲(類型/表達式).這些信息對模板非常有用.

    static if (__traits(isArithmetic, T)) {
        // ... 算術類型...

    } else {
        // ... 不是 ...
    }
//----
//類似,提供是否是符類型
import std.traits;

// ...

    static if (isSomeChar!T) {
        // ... char, wchar, 或 dchar ...

    } else {
        // ... 不是 ...
    }

有兩個地方提供相關有用信息:一,_ _traits,二,std.traits中的模板.
參考1參考2

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章