🙆
Zigの配列とスライスの型まとめ
想定読者
- zigの配列とスライスの型がいまいちピンと来ていない方
配列とスライスの関係
スライス = 配列へのポインタ + 配列のサイズ(usize)
配列の裏にはSliceがあるイメージです。
配列とスライスの型
データの型i32で要素数が5の場合は配列とスライスの型は次のようになります。
test "array_and_slice" {
var array = [_]i32{ 1, 2, 3, 4, 5 };
try std.testing.expectEqual([5]i32, @TypeOf(array));
var K: usize = 0;
var slice = array[0..K];
try std.testing.expectEqual([]i32, @TypeOf(slice));
}
配列の型は要素数を含んでいることが分かりますね。
varとconst
zigの変数はvar
とconst
の2種類の宣言方法があります。
ざっくり言うと、var
はmutable
な変数でconst
はimmutable
な変数です。(詳細は下記を参考にしてください。)
配列はvarとconstの2種類の宣言方法があります。
test "mutable_and_imutable_array" {
var mutable_array = [_]i32{ 1, 2, 3, 4, 5 };
try std.testing.expectEqual([5]i32, @TypeOf(mutable_array));
const immutable_array = [_]i32{ 1, 2, 3, 4, 5 };
try std.testing.expectEqual([5]i32, @TypeOf(immutable_array));
}
4種類のスライス
裏にある配列にvarとconstの2種類あり、スライス自身にもvarとconstの2種類あるため、スライスには次の4種類に分類することができます。
1. const宣言で定義された配列 + const宣言で定義されたスライス
2. const宣言で定義された配列 + var宣言で定義されたスライス
3. var宣言で定義された配列 + const宣言で定義されたスライス
4. var宣言で定義された配列 + var宣言で定義されたスライス
それぞれがどのような型になっているか見てみましょう。
配列がconstの場合のスライスの型
1. const宣言で定義された配列 + const宣言で定義されたスライス
2. const宣言で定義された配列 + var宣言で定義されたスライス
のパターンについては、どちらもconstなスライス型
になります。
test "slice_from_immutable_array" {
const immutable_array = [_]i32{ 1, 2, 3, 4, 5 };
try std.testing.expectEqual([5]i32, @TypeOf(immutable_array));
var K: usize = 0;
var mutable_slice = immutable_array[0..K];
try std.testing.expectEqual([]const i32, @TypeOf(mutable_slice));
const immutable_slice = immutable_array[0..K];
try std.testing.expectEqual([]const i32, @TypeOf(immutable_slice));
}
配列がvarの場合のスライスの型
test "slice_from_mutable_array" {
var mutable_array = [_]i32{ 1, 2, 3, 4, 5 };
try std.testing.expectEqual([5]i32, @TypeOf(mutable_array));
var K: usize = 0;
var mutable_slice = mutable_array[0..K];
try std.testing.expectEqual([]i32, @TypeOf(mutable_slice));
const immutable_slice = mutable_array[0..K];
try std.testing.expectEqual([]i32, @TypeOf(immutable_slice));
}
注意: コンパイル時に値の確定するスライスは配列のポインタになる
コンパイル時に値が確定していると、スライスはただの配列へのポインタとして扱われます。
test "slice_from_array" {
var array = [_]i32{ 1, 2, 3, 4, 5 };
var slice = array[0..];
try std.testing.expectEqual(*[5]i32, @TypeOf(slice));
}
まとめ
const std = @import("std");
const stdout = std.io.getStdOut().writer();
test "test_array_or_slice_from_immutable_array" {
const immutable_array = [_]i32{ 1, 2, 3, 4, 5 };
try std.testing.expectEqual([5]i32, @TypeOf(immutable_array));
var K: usize = 0;
var mutable_slice = immutable_array[0..K];
try std.testing.expectEqual([]const i32, @TypeOf(mutable_slice));
const immutable_slice = immutable_array[0..K];
try std.testing.expectEqual([]const i32, @TypeOf(immutable_slice));
// if the length of the slice is known at compile time,
// zig handle the type of the slice as a pointer to an array
var mutable_ptr_to_array = immutable_array[0..];
try std.testing.expectEqual(*const [5]i32, @TypeOf(mutable_ptr_to_array));
// if the length of the slice is unknown at compile time,
// zig handle the type of the slice as a pointer to an array
const immutable_ptr_to_array = immutable_array[0..];
try std.testing.expectEqual(*const [5]i32, @TypeOf(immutable_ptr_to_array));
}
test "test_array_and_slice_from_mutable_array" {
var mutable_array = [_]i32{ 1, 2, 3, 4, 5 };
try std.testing.expectEqual([5]i32, @TypeOf(mutable_array));
var K: usize = 0;
var mutable_slice = mutable_array[0..K];
try std.testing.expectEqual([]i32, @TypeOf(mutable_slice));
const immutable_slice = mutable_array[0..K];
try std.testing.expectEqual([]i32, @TypeOf(immutable_slice));
// if the length of the slice is known at compile time,
// zig handle the type of the slice as a pointer to an array
var mutable_ptr_to_array = mutable_array[0..];
try std.testing.expectEqual(*[5]i32, @TypeOf(mutable_ptr_to_array));
// if the length of the slice is unknown at compile time,
// zig handle the type of the slice as a pointer to an array
const immutable_ptr_to_array = mutable_array[0..];
try std.testing.expectEqual(*[5]i32, @TypeOf(immutable_ptr_to_array));
}
Discussion