authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-06-25 16:28:27-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-06-25 16:28:27-07:00
log4c5394b367562ccca37f66ef64cb2b3978c0c283
treedecce3d323bdab00a8ee196554ade52c79571851
parent7db2ef6104921c42ce42e8edda848160eda8973d

langref: make section for slice by length


3 files changed, 31 insertions(+), 10 deletions(-)

doc/langref.html.in+19-1
......@@ -1955,7 +1955,7 @@ or
19551955 TODO talk about C ABI interop<br>
19561956 TODO consider suggesting std.MultiArrayList
19571957 </p>
1958 {#see_also|@splat|@shuffle|@select|@reduce#}
1958 {#see_also|@splat|@shuffle|@select|@reduce|Slicing by Length#}
19591959
19601960 {#header_open|Relationship with Arrays#}
19611961 <p>Vectors and {#link|Arrays#} each have a well-defined <strong>bit layout</strong>
......@@ -2150,6 +2150,24 @@ or
21502150
21512151 {#see_also|Pointers|for|Arrays#}
21522152
2153 {#header_open|Slicing by Length#}
2154 <p>Even though Zig only has syntax for slicing based on start and end indices, by slicing twice,
2155 one can express a <strong>slice by length</strong> operation.</p>
2156 <p>The pattern {#syntax#}[a .. a + b]{#endsyntax#} is always better expressed
2157 {#syntax#}[a..][0..b]{#endsyntax#} because:</p>
2158 <ul>
2159 <li>Slices are represented in memory as a pointer and length. Despite
2160 syntactically appearing as twice the work, it is actually one less
2161 subtraction in machine code.</li>
2162 <li>If {#syntax#}a{#endsyntax#} is known at runtime and
2163 {#syntax#}b{#endsyntax#} is known at {#link|comptime#}, the former
2164 results in a slice but the latter results in a single-item
2165 {#link|pointer|Pointers#} to an {#link|array|Arrays#}, a generally more
2166 safe type because the length is compile-time known.</li>
2167 </ul>
2168 {#code|slicing_by_length.zig#}
2169 {#header_close#}
2170
21532171 {#header_open|Sentinel-Terminated Slices#}
21542172 <p>
21552173 The syntax {#syntax#}[:x]T{#endsyntax#} is a slice which has a runtime-known length
doc/langref/slicing_by_length.zig created+12
......@@ -0,0 +1,12 @@
1const expectEqual = @import("std").testing.expectEqual;
2
3test "example" {
4 var array = [_]i32{ 1, 2, 3, 4 };
5 var runtime_start: usize = 1;
6 _ = &runtime_start;
7 const length = 2;
8 const array_ptr_len = array[runtime_start..][0..length];
9 try expectEqual(*[length]i32, @TypeOf(array_ptr_len));
10}
11
12// test
doc/langref/test_basic_slices.zig-9
......@@ -21,15 +21,6 @@ test "basic slices" {
2121 const array_ptr = array[0..array.len];
2222 try expectEqual(*[array.len]i32, @TypeOf(array_ptr));
2323
24 // You can perform a slice-by-length by slicing twice. This allows the compiler
25 // to perform some optimisations like recognising a comptime-known length when
26 // the start position is only known at runtime.
27 var runtime_start: usize = 1;
28 _ = &runtime_start;
29 const length = 2;
30 const array_ptr_len = array[runtime_start..][0..length];
31 try expectEqual(*[length]i32, @TypeOf(array_ptr_len));
32
3324 // Using the address-of operator on a slice gives a single-item pointer.
3425 try expectEqual(*i32, @TypeOf(&slice[0]));
3526 // Using the `ptr` field gives a many-item pointer.