オフィスアワーがそろそろ始まるよ!()

暗黙の型変換と明示的な型変換

型変換 (キャスト) とは、ある型を別の型に変換することです。Zenには暗黙の型変換明示的な型変換があります。

暗黙の型変換は、型変換が安全であることが保証されている場合に、プログラマが明示的に書かなくても行われる型変換です。明示的な型変換は、Zenの組込み関数を用いてプログラマが明示的に行う型変換です。

暗黙の型変換

ある型が求められている時に、異なる型を渡した際、暗黙の型変換が発生します。暗黙の型変換は、曖昧さがなく、その型変換が安全な場合のみ発生します。

よりビット数が多い数値型への変換

整数型では、変換元の整数型の全ての値が、変換後の整数型で表現可能な場合、暗黙の型変換が働きます。わかりやすい変換は、より広いビット幅をもつ整数型 (符号なし→符号なし、または、符号あり→符号あり) です。

examples/ch11-advanced/cast/src/widening_number.zen:4:18

test "integer widening" {
    var x: u8 = 250;
    // u8 => u16
    var y: u16 = x;
    ok(x == y);

    // u8 => u9
    var z: u9 = x;
    ok(x == z);

    var xi: i8 = -127;
    // i8 => i16
    var yi: i16 = xi;
    ok(xi == yi);
}

符号なしから符号ありに変換する場合、変換後の符号あり整数型は、変換元の符号なし整数型より、1ビット以上広いビット幅が必要です。次の例で変数zi9型です。i9型は-256から255の数値を表現でき、u8型が取りうる0から255を全て表現できるため、暗黙の型変換が可能です。

examples/ch11-advanced/cast/src/widening_number.zen:20:27

test "unsigned integer to signed integer" {
    var x: u8 = 255;
    var y: i16 = x;
    ok(y == 255);

    var z: i9 = x;
    ok(z == 255);
}

浮動小数点型も同様に、より広いビット幅を持つ型に変換できます。

examples/ch11-advanced/cast/src/widening_number.zen:29:34

test "float widening" {
    var x: f16 = 1234.5678;
    var y: f32 = x;
    var z: f64 = y;
    ok(x == z);
}```

#### より制約の強い修飾子が付いている型への変換

`const`と`volatile`はある型に対して、より厳しい制約を課しています。ある型`T`を、`const T`や`volatile T`に変換する場合、暗黙の型変換が働きます。

<p align="right">
examples/ch11-advanced/cast/src/qualification.zen:4:10
</p>

```zen
test "const qualification" {
    var x: u32 = 42;
    const ptr: *u32 = &x;
    // *u32 => *const u32
    const const_ptr: *const u32 = ptr;
    ok(ptr == const_ptr);
}

alignはある型に対して、より小さいアライメントを指定すると制約が強くなります。そのため、より小さいアライメントを求める場合、暗黙の型変換が働きます。

examples/ch11-advanced/cast/src/qualification.zen:12:15

test "smaller alignment" {
    var x: u32 align(8) = 42;
    var y: u32 align(4) = x;
}

配列とポインタ

配列とポインタ (ファットポインタであるスライスを含む) とは、一定の条件を満たしている場合、暗黙の型変換が働きます。

配列へのポインタからスライス

配列へのポインタ (*[N]T) からスライス ([]T) へと変換する際、暗黙の型変換が働きます。

examples/ch11-advanced/cast/src/arrays_and_pointers.zen:5:12

test "pointer to an array to slice" {
    var a: [5]u8 = "hello";
    // [5]u8 => []u8
    const s: []u8 = &a;
    equalSlices(u8, s, "hello");
    // スライスの要素数は配列の要素数と同じ
    ok(s.len == a.len);
}
配列へのポインタから要素数が不明なポインタ

配列へのポインタ (*[N]T) から要素数が不明なポインタ ([*]T) へと変換する際、暗黙の型変換が働きます。

examples/ch11-advanced/cast/src/arrays_and_pointers.zen:14:18

test "pointer to an array to unknown length pointer" {
    var a: [5]u8 = "hello";
    const unknown_length: [*]u8 = &a;
    ok(unknown_length[4] == 'o');
}

この暗黙の型変換は、C言語との相互運用で役立ちますが、一般的にはあまり利用すべきでありません。

オプション型

オプション型 (?T) に対して、Tnullから?Tに変換する場合、暗黙の型変換が働きます。

examples/ch11-advanced/cast/src/optional.zen:4:10

test "casting to optional" {
    const x: ?u32 = 42;
    const y: ?u32 = null;

    ok(x.? == 42);
    ok(y == null);
}

エラー共用体

エラー共用体 (E!T) に対して、エラー型ETからE!Tに変換する場合、暗黙の型変換が働きます。

examples/ch11-advanced/cast/src/error_union.zen:5:16

const Error = error {
    A,
    B,
};

test "cast to error union" {
    const x: Error!u32 = 42;
    const y: Error!u32 = Error.A;

    ok((try x) == 42);
    err(Error.A, y);
}

コンパイル時計算可能な整数

コンパイル時計算可能な整数は、が変換後の整数型の範囲内である場合、暗黙の型変換が働きます。コンパイル時計算可能な整数には、コンパイル時整数 (comptime_int) と、コンパイル時計算可能な整数を代入したconst変数とが、該当します。

examples/ch11-advanced/cast/src/comptime_kwnon.zen:4:14

test "casting comptime known integers" {
    // xは`comptime_int`型
    const x = 255;
    // comptime_int => u64
    // `y`はコンパイル時計算可能な整数
    const y: u64 = x;
    // u64 => u8
    // `y`の「値」は`255`であることがコンパイル時計算可能なため
    // 暗黙の型変換が働く
    const z: u8 = y;
}

タグ付き共用体から列挙型

タグ付き共用体を列挙型に型変換する場合、暗黙の型変換が働きます。

examples/ch11-advanced/cast/src/tagged_union.zen:4:19

const Tag = enum {
    U32,
    F64,
};

const Value = union(Tag) {
    U32: u32,
    F64: f64,
};

test "casting tagged union to enum" {
    var value = Value { .U32 = 42 };
    // Value => Tag
    var tag: Tag = value;
    ok(tag == Tag.U32);
}

undefined

undefinedはあらゆる型に対して、暗黙の型変換が働きます。

明示的な型変換

明示的な型変換はZen言語の組込み関数を利用して行います。明示的な型変換は、未定義動作を引き起す可能性があります。未定義動作を引き起こす条件と、対策方法は11.1 未定義動作を参照して下さい。

いくつかの明示的な型変換に対しては、言語レベルのチェックが入っています。例えば、@intCastは引数の型に整数型しか受け付けません。

組込み関数 説明
@bitCast ビット表現を変更せずに型を変換します
@alignCast ポインタのアライメントを変換します
@boolToInt trueを1に、falseを0に、変換します
@bytesToSlice u8のスライスを別の要素型のスライスに変換します
@enumToInt 列挙型もしくはタグ付き共用体からタグの整数値を取得します
@errSetCast エラー型をサブセットのエラー型に変換します
@errorToInt エラー種別の整数値を取得します
@floatCast よりビット幅の少ない浮動小数点型に変換します
@floatToInt 浮動小数点値の整数部分を取得します
@intCast 整数型同士を変換します
@intToEnum 整数値から列挙型の値を取得します
@intToError 整数値からエラー種別を取得します
@intToFloat 整数値を浮動小数点値に変換します
@intToPtr アドレスをポインタに変換します
@ptrCast ポインタ型同士を変換します
@ptrToInt ポインタからアドレスに変換します
@sliceToBytes 何らかの要素型のスライスからu8のスライスへ変換します
@truncate 整数型同士の変換を行い、上位ビットを切り捨てます

☰ 人の生きた証は永遠に残るよう ☰
Copyright © 2018-2019 connectFree Corporation. All rights reserved.
Zen, the Zen three-circles logo and The Zen Programming Language are trademarks of connectFree corporation in Japan and other countries.