Slices

test.zig

  1. const expect = @import("std").testing.expect;
  2. test "basic slices" {
  3. var array = [_]i32{ 1, 2, 3, 4 };
  4. // A slice is a pointer and a length. The difference between an array and
  5. // a slice is that the array's length is part of the type and known at
  6. // compile-time, whereas the slice's length is known at runtime.
  7. // Both can be accessed with the `len` field.
  8. var known_at_runtime_zero: usize = 0;
  9. const slice = array[known_at_runtime_zero..array.len];
  10. try expect(&slice[0] == &array[0]);
  11. try expect(slice.len == array.len);
  12. // Using the address-of operator on a slice gives a single-item pointer,
  13. // while using the `ptr` field gives a many-item pointer.
  14. try expect(@TypeOf(slice.ptr) == [*]i32);
  15. try expect(@TypeOf(&slice[0]) == *i32);
  16. try expect(@ptrToInt(slice.ptr) == @ptrToInt(&slice[0]));
  17. // Slices have array bounds checking. If you try to access something out
  18. // of bounds, you'll get a safety check failure:
  19. slice[10] += 1;
  20. // Note that `slice.ptr` does not invoke safety checking, while `&slice[0]`
  21. // asserts that the slice has len >= 1.
  22. }
  1. $ zig test test.zig
  2. Test [1/1] test "basic slices"...
  3. thread 10827 panic: index out of bounds
  4. /home/andy/Downloads/zig/docgen_tmp/test.zig:22:10: 0x2069b3 in test "basic slices" (test)
  5. slice[10] += 1;
  6. ^
  7. /home/andy/Downloads/zig/lib/std/special/test_runner.zig:76:28: 0x22d2da in std.special.main (test)
  8. } else test_fn.func();
  9. ^
  10. /home/andy/Downloads/zig/lib/std/start.zig:471:37: 0x22583a in std.start.callMain (test)
  11. const result = root.main() catch |err| {
  12. ^
  13. /home/andy/Downloads/zig/lib/std/start.zig:413:12: 0x20970e in std.start.callMainWithArgs (test)
  14. return @call(.{ .modifier = .always_inline }, callMain, .{});
  15. ^
  16. /home/andy/Downloads/zig/lib/std/start.zig:332:17: 0x208736 in std.start.posixCallMainAndExit (test)
  17. std.os.exit(@call(.{ .modifier = .always_inline }, callMainWithArgs, .{ argc, argv, envp }));
  18. ^
  19. /home/andy/Downloads/zig/lib/std/start.zig:245:5: 0x208542 in std.start._start (test)
  20. @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
  21. ^
  22. error: the following test command crashed:
  23. docgen_tmp/zig-cache/o/333a8741816702dafd0ff99af380ebb1/test /home/andy/Downloads/zig/build-release/zig

This is one reason we prefer slices to pointers.

slices.zig

  1. const std = @import("std");
  2. const expect = std.testing.expect;
  3. const mem = std.mem;
  4. const fmt = std.fmt;
  5. test "using slices for strings" {
  6. // Zig has no concept of strings. String literals are const pointers
  7. // to null-terminated arrays of u8, and by convention parameters
  8. // that are "strings" are expected to be UTF-8 encoded slices of u8.
  9. // Here we coerce *const [5:0]u8 and *const [6:0]u8 to []const u8
  10. const hello: []const u8 = "hello";
  11. const world: []const u8 = "世界";
  12. var all_together: [100]u8 = undefined;
  13. // You can use slice syntax on an array to convert an array into a slice.
  14. const all_together_slice = all_together[0..];
  15. // String concatenation example.
  16. const hello_world = try fmt.bufPrint(all_together_slice, "{s} {s}", .{ hello, world });
  17. // Generally, you can use UTF-8 and not worry about whether something is a
  18. // string. If you don't need to deal with individual characters, no need
  19. // to decode.
  20. try expect(mem.eql(u8, hello_world, "hello 世界"));
  21. }
  22. test "slice pointer" {
  23. var array: [10]u8 = undefined;
  24. const ptr = &array;
  25. // You can use slicing syntax to convert a pointer into a slice:
  26. const slice = ptr[0..5];
  27. slice[2] = 3;
  28. try expect(slice[2] == 3);
  29. // The slice is mutable because we sliced a mutable pointer.
  30. // Furthermore, it is actually a pointer to an array, since the start
  31. // and end indexes were both comptime-known.
  32. try expect(@TypeOf(slice) == *[5]u8);
  33. // You can also slice a slice:
  34. const slice2 = slice[2..3];
  35. try expect(slice2.len == 1);
  36. try expect(slice2[0] == 3);
  37. }
  1. $ zig test slices.zig
  2. Test [1/2] test "using slices for strings"...
  3. Test [2/2] test "slice pointer"...
  4. All 2 tests passed.

See also:

Sentinel-Terminated Slices

The syntax [:x]T is a slice which has a runtime known length and also guarantees a sentinel value at the element indexed by the length. The type does not guarantee that there are no sentinel elements before that. Sentinel-terminated slices allow element access to the len index.

null_terminated_slice.zig

  1. const std = @import("std");
  2. const expect = std.testing.expect;
  3. test "null terminated slice" {
  4. const slice: [:0]const u8 = "hello";
  5. try expect(slice.len == 5);
  6. try expect(slice[5] == 0);
  7. }
  1. $ zig test null_terminated_slice.zig
  2. Test [1/1] test "null terminated slice"...
  3. All 1 tests passed.

See also: