45用d编程元组

元组Tuple,是std.typecons实现的库特征.合并多个值进一个值.
利用std.metaAliasSeq来完成某些操作.
更多可见此

import std.stdio;
import std.typecons;

void main() {
    auto t = tuple(42, "hello");//可用tuple构建
    writeln(t);//Tuple!(int, string)(42, "hello")
}

等价于:

//等价Tuple!(int, string)
struct __Tuple_int_string {
    int __member_0;
    string __member_1;
}
//这样访问
    writeln(t[0]);
    writeln(t[1]);

还可以这样:

    auto t = Tuple!(int, "number",string, "message")(42, "hello");
//相当于别名,或者说一个结构的成员的名字,两个两个的
    writeln("by index 0 : ", t[0]);
    writeln("by .number : ", t.number);
    writeln("by index 1 : ", t[1]);
    writeln("by .message: ", t.message);
//相当于定义了一个结构了.

元组可变为值列表,这样就可以直接传入参数了.

import std.stdio;
import std.typecons;

void foo(int i, string s, double d, char c) {
    // ...
}

void bar(int i, double d, char c) {
    // ...
}

void main() {
    auto t = tuple(1, "2", 3.3, '4');
    // foo(1, "2", 3.3, '4'):
    foo(t.expand);//可扩展一下,就进去了.
    foo(t[]);//等价于上面的形式
    bar(t[0],t[$-2..$]);//等价于bar(1, 3.3, '4')
}

还可以这样:

import std.stdio;
import std.typecons;

void main() {
    auto t = tuple(1, 2, 3);
    auto a = [ t.expand, t[] ];//扩展,应是值类型
    //要求类型匹配.这样a就相当于字面量了.
    writeln(a);
}

编译时foreach

    auto t = tuple(42, "hello", 1.5);
    foreach (i, member; t) {//编译时
        writefln("%s: %s", i, member);
    }

看起来像运行时,实际上不是,实质是:

    {
        enum size_t i = 0;
        int member = t[i];
        writefln("%s: %s", i, member);
    }
    {
        enum size_t i = 1;
        string member = t[i];
        writefln("%s: %s", i, member);
    }
    {
        enum size_t i = 2;
        double member = t[i];
        writefln("%s: %s", i, member);
    }

每一对元组执行展开操作.主要是元组类型不同,所以都得展开.
同时,可以一次返回一个元组,如std.algorithm.findSplit

import std.algorithm;

// ...

    auto entireRange = "hello";
    auto searched = "ll";

    auto result=findSplit(entireRange, searched);

    writeln("before: ", result[0]);
    writeln("found : ", result[1]);
    writeln("after : ", result[2]);

或者是返回结构:

struct Result {
    // ...
}

Result foo() {
    // ...
}

std.meta中定义的AliasSeq.表示的是编译器常用,而编程作为实体不可用的概念.如,分隔的值,类型,符号(如 别名模板参数).3个例子:函数参数列表,模板参数列表,数组字面量元素列表

   foo(1, "hello", 2.5);
    auto o = Bar!(char, long)();
    auto a = [ 1, 2, 3, 4 ]; 

元组扩展成员时利用它.AliasSeq包含类型,值,符号.
AliasSeq 和 std.meta,过去为TypeTuple 和 std.typetuple
本章包含仅值和仅类型.在可变模板中特别有用.

扫描二维码关注公众号,回复: 10045595 查看本文章
import std.stdio;

void foo(int i, string s, double d) {
    writefln("用%s, %s, 和 %s调用foo.", i, s, d);
}

限定AliasSeq的值为模板参数.包含值/类型
一般这样调用foo(1, "hello", 2.5);,
现在可以这样:

import std.meta;

// ...
alias arguments = AliasSeq!(1, "hello", 2.5);
foo(arguments);

将参数打包为一个别名序列了.
arguments,是AliasSeq模板的一个实例的别名.
还可用AliasSeq来实例化数组.即就是一个序列.

    alias elements = AliasSeq!(1, 2, 3, 4);
    auto arr = [ elements ];//但要元素类型匹配
    assert(arr == [ 1, 2, 3, 4 ]);

索引与切片.

   alias arguments = AliasSeq!(1, "hello", 2.5);
    assert(arguments[0] == 1);
    assert(arguments[1] == "hello");
    assert(arguments[2] == 2.5);//就是一个序列

还可以像这样:

void bar(string s, double d) {
    // ...
}
// ...
    bar(arguments[$-2 .. $]);//最后两位参数匹配

包含类型列表,即(整,双精…)

import std.conv;

struct S(ElementT, ResultT) {//元素类型,返回类型
    ElementT[] arr;
    ResultT length() {
        return to!ResultT(arr.length);
    }
}

void main() {
    auto s = S!(double, int)([ 1, 2, 3 ]);
    auto l = s.length();
}

看看

import std.meta;

// ...

    alias Types = AliasSeq!(double, int);
    auto s = S!Types([ 1, 2, 3 ]);//现在别名为类型序列了

看起来像单个参数,使用时自动扩展了,在可变模板中很有用.
AliasSeq还可与foreach搭配.而且是在编译时,为每个成员展开.

unittest {
    alias Types = AliasSeq!(int, long, float);
    foreach (Type; Types) {
        auto s = S!(Type, size_t)([ Type.init, Type.init ]);
        assert(s.length() == 2);
    }
}
//变成这样
    {
        auto s = S!(int, size_t)([ int.init, int.init ]);
        assert(s.length() == 2);
    }
    {//整,长,浮,展开
        auto s = S!(long, size_t)([ long.init, long.init ]);
        assert(s.length() == 2);
    }
    {
        auto s = S!(float, size_t)([ float.init, float.init ]);
        assert(s.length() == 2);
    }

.tupleof属性.展示类型/对象成员.对自定义类型,可访问类型成员的定义.

import std.stdio;

struct S {
    int number;
    string message;
    double value;
}

void main() {
    foreach (i, MemberType; typeof(S.tupleof)){
        writefln("Member %s:", i);
        writefln("type: %s", MemberType.stringof);
        string name = S.tupleof[i].stringof;
        writefln("  name: %s", name);
    }//对类型的每一.
}

第一个应用.tupleoftypeof,来取元素们的类型
他们的名字由S.tupleof[i].stringof来取
tupleof取的是值.也可作用于对象.

    auto object = S(42, "hello", 1.5);

    foreach (i, member; object.tupleof) {
        writefln("成员 %s:", i);
        writefln("类型 : %s", typeof(member).stringof);
        writefln("值: %s", member);
    }

有两套系统值和类型系统.要注意,元组对象自身成员的引用,不是副本.
元组合并多个值就像一个结构一样,一般为临时少量使用.没有名字.
显式使用时,允许按属性访问成员.
可用.扩展或切片扩展
每一元组不是运行时循环,而是编译时展开

发布了440 篇原创文章 · 获赞 29 · 访问量 11万+

猜你喜欢

转载自blog.csdn.net/fqbqrr/article/details/104590007