演员到底做了什么?

What does cast do exactly?

我在玩整数数组散列以及从一种表示到另一种表示的不同方式。我最终得到以下结果:

void main(string[] args) {
    import std.algorithm, std.array, std.conv, std.stdio, std.digest.md;

    union hashU {
        ubyte[] hashA;
        int[]   hashN;
    };

    hashU a;
    auto md5 = new MD5Digest();

    a.hashN = [1, 2, 3, 4, 5];

    /* Using an union, no actual data conversion */
    md5.put( a.hashA );
    auto hash = md5.finish();
    writeln(hash);
    // [253, 255, 63, 4, 193, 99, 182, 232, 28, 231, 57, 107, 18, 254, 75, 175]

    /* Using a cast... Doesn't match any of the other representations */
    md5.put( cast(ubyte[])(a.hashN) );
    hash = md5.finish();
    writeln(hash);
    // [254, 5, 74, 210, 231, 185, 139, 238, 103, 63, 159, 242, 45, 80, 240, 12]

    /* Using .to! to convert from array to array */
    md5.put( a.hashN.to!(ubyte[]) );
    hash = md5.finish();
    writeln(hash);
    // [124, 253, 208, 120, 137, 179, 41, 93, 106, 85, 9, 20, 171, 53, 224, 104]

    /* This matches the previous transformation */
    md5.put( a.hashN.map!(x => x.to!ubyte).array );
    hash = md5.finish();
    writeln(hash);
    // [124, 253, 208, 120, 137, 179, 41, 93, 106, 85, 9, 20, 171, 53, 224, 104]
}

我的问题如下:演员是做什么的?我原以为它会和 .to 一样!或 union 技巧,但似乎并非如此。

据我所知,强制转换只是告诉编译器开始与您强制转换的内存块对话。

您示例中的最后两个选项实际上将数字转换为新类型,实际 工作也是如此。这就是为什么它们最终具有相同的值。

前两个示例中的问题是 int[] 在内存中比 ubyte[] 大。 (每个元素 4 个字节 vs 每个元素 1 个字节)

我已经编辑了你的前两个方法:

    /* Using an union, no actual data conversion */
md5.put( a.hashA );
auto hash = md5.finish();
writefln("Hash of: %s -> %s", a.hashA, hash);
// Hash of: [1, 0, 0, 0, 2] -> [253, 255, 63, 4, 193, 99, 182, 232, 28, 231, 57, 107, 18, 254, 75, 175] 
// notice 5 bytes in first array

/* Using a cast... Doesn't match any of the other representations */
md5.put( cast(ubyte[])(a.hashN) );
hash = md5.finish();
writefln("Hash of: %s -> %s", cast(ubyte[])(a.hashN), hash);
// Hash of: [1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0, 5, 0, 0, 0] -> [254, 5, 74, 210, 231, 185, 139, 238, 103, 63, 159, 242, 45, 80, 240, 12] 
// notice 20 bytes (4 x 5 bytes) in first array

因此,首先,您正在读取 ubyte[] 的字节长度。在第二个中,您将 int[] 的长度转换为 ubyte[].

编辑:概率不明确。联合非常愚蠢,它只是将所有值存储在同一内存中。当您读取其中任何一个时,它只会读取该内存的 X 位,具体取决于您正在读取的类型的长度。

所以因为你正在读取 int[] 然后转换它,它读取所有 20 个字节并将它们转换为 ubyte[]。这当然不同于仅仅读取 ubyte[] 变量的 5 个字节。

我觉得我说得有道理:)

我觉得 Colin Grogan 说得对,但是他的措辞有点混乱。

使用联合,数组被简单地重新解释,根本没有 calculation/computation 发生。 int[] 的指针和长度被重新解释为引用 ubyte 元素。之前:5 个整数,之后:5 个字节。

转换比这更聪明:它调整数组的长度,使其引用与以前相同的内存。之前:5 个整数,之后:20 ubytes (5*int.sizeof/ubyte.sizeof = 5*4/1 = 20).

union 和 cast 都将 int 的字节重新解释为 ubyte。也就是说,int 值 1 将产生 4 个 ubytes:0,0,0,1 或 1,0,0,0,具体取决于字节顺序。

to 变体将每个元素转换为新的元素类型。之前:5 个整数,之后:5 个字节,与整数具有相同的值。如果其中一个整数无法转换为 ubyte,to 将抛出异常。

在各种转换后打印元素可能有助于阐明发生了什么:

void main()
{
    import std.algorithm, std.array, std.conv, std.stdio;

    union hashU
    {
        ubyte[] hashA;
        int[]   hashN;
    }
    hashU a;
    a.hashN = [1, 2, 3, 4, 5];

    writeln( a.hashA ); /* union -> [1, 0, 0, 0, 2] (depends on endianess) */

    writeln( cast(ubyte[])(a.hashN) );
        /* cast -> [1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0, 5, 0, 0, 0]
        (depends on endianess) */

    writeln( a.hashN.to!(ubyte[]) ); /* `to` -> [1, 2, 3, 4, 5] */
}

cast是开发者需要进行显式类型转换时使用的D运算符