Slices
test.zig
const assert = @import("std").debug.assert;
test "basic slices" {
var array = [_]i32{ 1, 2, 3, 4 };
// A slice is a pointer and a length. The difference between an array and
// a slice is that the array's length is part of the type and known at
// compile-time, whereas the slice's length is known at runtime.
// Both can be accessed with the `len` field.
const slice = array[0..array.len];
assert(&slice[0] == &array[0]);
assert(slice.len == array.len);
// Using the address-of operator on a slice gives a pointer to a single
// item, while using the `ptr` field gives an unknown length pointer.
assert(@typeOf(slice.ptr) == [*]i32);
assert(@typeOf(&slice[0]) == *i32);
assert(@ptrToInt(slice.ptr) == @ptrToInt(&slice[0]));
// Slices have array bounds checking. If you try to access something out
// of bounds, you'll get a safety check failure:
slice[10] += 1;
// Note that `slice.ptr` does not invoke safety checking, while `&slice[0]`
// asserts that the slice has len >= 1.
}
$ zig test test.zig
1/1 test "basic slices"...index out of bounds
/home/andy/dev/zig/docgen_tmp/test.zig:21:10: 0x205684 in test "basic slices" (test)
slice[10] += 1;
^
/home/andy/dev/zig/lib/std/special/test_runner.zig:13:25: 0x2284e1 in std.special.main (test)
if (test_fn.func()) |_| {
^
/home/andy/dev/zig/lib/std/special/start.zig:204:37: 0x227355 in std.special.posixCallMainAndExit (test)
const result = root.main() catch |err| {
^
/home/andy/dev/zig/lib/std/special/start.zig:102:5: 0x2271cf in std.special._start (test)
@noInlineCall(posixCallMainAndExit);
^
Tests failed. Use the following command to reproduce the failure:
/home/andy/dev/zig/docgen_tmp/test
This is one reason we prefer slices to pointers.
slices.zig
const assert = @import("std").debug.assert;
const mem = @import("std").mem;
const fmt = @import("std").fmt;
test "using slices for strings" {
// Zig has no concept of strings. String literals are arrays of u8, and
// in general the string type is []u8 (slice of u8).
// Here we implicitly cast [5]u8 to []const u8
const hello: []const u8 = "hello";
const world: []const u8 = "世界";
var all_together: [100]u8 = undefined;
// You can use slice syntax on an array to convert an array into a slice.
const all_together_slice = all_together[0..];
// String concatenation example.
const hello_world = try fmt.bufPrint(all_together_slice, "{} {}", hello, world);
// Generally, you can use UTF-8 and not worry about whether something is a
// string. If you don't need to deal with individual characters, no need
// to decode.
assert(mem.eql(u8, hello_world, "hello 世界"));
}
test "slice pointer" {
var array: [10]u8 = undefined;
const ptr = &array;
// You can use slicing syntax to convert a pointer into a slice:
const slice = ptr[0..5];
slice[2] = 3;
assert(slice[2] == 3);
// The slice is mutable because we sliced a mutable pointer.
assert(@typeOf(slice) == []u8);
// You can also slice a slice:
const slice2 = slice[2..3];
assert(slice2.len == 1);
assert(slice2[0] == 3);
}
test "slice widening" {
// Zig supports slice widening and slice narrowing. Cast a slice of u8
// to a slice of anything else, and Zig will perform the length conversion.
const array align(@alignOf(u32)) = [_]u8{ 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13 };
const slice = @bytesToSlice(u32, array[0..]);
assert(slice.len == 2);
assert(slice[0] == 0x12121212);
assert(slice[1] == 0x13131313);
}
$ zig test slices.zig
1/3 test "using slices for strings"...OK
2/3 test "slice pointer"...OK
3/3 test "slice widening"...OK
All tests passed.
See also: