Values

values.zig

  1. // Top-level declarations are order-independent:
  2. const print = std.debug.print;
  3. const std = @import("std");
  4. const os = std.os;
  5. const assert = std.debug.assert;
  6. pub fn main() void {
  7. // integers
  8. const one_plus_one: i32 = 1 + 1;
  9. print("1 + 1 = {}\n", .{one_plus_one});
  10. // floats
  11. const seven_div_three: f32 = 7.0 / 3.0;
  12. print("7.0 / 3.0 = {}\n", .{seven_div_three});
  13. // boolean
  14. print("{}\n{}\n{}\n", .{
  15. true and false,
  16. true or false,
  17. !true,
  18. });
  19. // optional
  20. var optional_value: ?[]const u8 = null;
  21. assert(optional_value == null);
  22. print("\noptional 1\ntype: {}\nvalue: {}\n", .{
  23. @typeName(@TypeOf(optional_value)),
  24. optional_value,
  25. });
  26. optional_value = "hi";
  27. assert(optional_value != null);
  28. print("\noptional 2\ntype: {}\nvalue: {}\n", .{
  29. @typeName(@TypeOf(optional_value)),
  30. optional_value,
  31. });
  32. // error union
  33. var number_or_error: anyerror!i32 = error.ArgNotFound;
  34. print("\nerror union 1\ntype: {}\nvalue: {}\n", .{
  35. @typeName(@TypeOf(number_or_error)),
  36. number_or_error,
  37. });
  38. number_or_error = 1234;
  39. print("\nerror union 2\ntype: {}\nvalue: {}\n", .{
  40. @typeName(@TypeOf(number_or_error)),
  41. number_or_error,
  42. });
  43. }
  1. $ zig build-exe values.zig
  2. $ ./values
  3. 1 + 1 = 2
  4. 7.0 / 3.0 = 2.33333325e+00
  5. false
  6. true
  7. false
  8. optional 1
  9. type: ?[]const u8
  10. value: null
  11. optional 2
  12. type: ?[]const u8
  13. value: hi
  14. error union 1
  15. type: anyerror!i32
  16. value: error.ArgNotFound
  17. error union 2
  18. type: anyerror!i32
  19. value: 1234

Primitive Types

NameC EquivalentDescription
i8int8_tsigned 8-bit integer
u8uint8_tunsigned 8-bit integer
i16int16_tsigned 16-bit integer
u16uint16_tunsigned 16-bit integer
i32int32_tsigned 32-bit integer
u32uint32_tunsigned 32-bit integer
i64int64_tsigned 64-bit integer
u64uint64_tunsigned 64-bit integer
i128int128signed 128-bit integer
u128unsigned int128unsigned 128-bit integer
isizeintptr_tsigned pointer sized integer
usizeuintptr_tunsigned pointer sized integer
c_shortshortfor ABI compatibility with C
c_ushortunsigned shortfor ABI compatibility with C
c_intintfor ABI compatibility with C
c_uintunsigned intfor ABI compatibility with C
c_longlongfor ABI compatibility with C
c_ulongunsigned longfor ABI compatibility with C
c_longlonglong longfor ABI compatibility with C
c_ulonglongunsigned long longfor ABI compatibility with C
c_longdoublelong doublefor ABI compatibility with C
c_voidvoidfor ABI compatibility with C
f16_Float1616-bit floating point (10-bit mantissa) IEEE-754-2008 binary16
f32float32-bit floating point (23-bit mantissa) IEEE-754-2008 binary32
f64double64-bit floating point (52-bit mantissa) IEEE-754-2008 binary64
f128_Float128128-bit floating point (112-bit mantissa) IEEE-754-2008 binary128
boolbooltrue or false
void(none)0 bit type
noreturn(none)the type of break, continue, return, unreachable, and while (true) {}
type(none)the type of types
anyerror(none)an error code
comptime_int(none)Only allowed for comptime-known values. The type of integer literals.
comptime_float(none)Only allowed for comptime-known values. The type of float literals.

In addition to the integer types above, arbitrary bit-width integers can be referenced by using an identifier of i or u followed by digits. For example, the identifier i7 refers to a signed 7-bit integer. The maximum allowed bit-width of an integer type is 65535.

See also:

Primitive Values

NameDescription
true and falsebool values
nullused to set an optional type to null
undefinedused to leave a value unspecified

See also:

String Literals and Character Literals

String literals are single-item constant Pointers to null-terminated UTF-8 encoded byte arrays. The type of string literals encodes both the length, and the fact that they are null-terminated, and thus they can be coerced to both Slices and Null-Terminated Pointers. Dereferencing string literals converts them to Arrays.

Character literals have type comptime_int, the same as Integer Literals. All Escape Sequences are valid in both string literals and character literals.

test.zig

  1. const expect = @import("std").testing.expect;
  2. const mem = @import("std").mem;
  3. test "string literals" {
  4. const bytes = "hello";
  5. expect(@TypeOf(bytes) == *const [5:0]u8);
  6. expect(bytes.len == 5);
  7. expect(bytes[1] == 'e');
  8. expect(bytes[5] == 0);
  9. expect('e' == '\x65');
  10. expect('\u{1f4a9}' == 128169);
  11. expect('💯' == 128175);
  12. expect(mem.eql(u8, "hello", "h\x65llo"));
  13. }
  1. $ zig test test.zig
  2. 1/1 test "string literals"... OK
  3. All 1 tests passed.

See also:

Escape Sequences

Escape SequenceName
\nNewline
\rCarriage Return
\tTab
\Backslash
\’Single Quote
\”Double Quote
\xNNhexadecimal 8-bit character code (2 digits)
\u{NNNNNN}hexadecimal Unicode character code UTF-8 encoded (1 or more digits)

Note that the maximum valid Unicode point is 0x10ffff.

Multiline String Literals

Multiline string literals have no escapes and can span across multiple lines. To start a multiline string literal, use the \\ token. Just like a comment, the string literal goes until the end of the line. The end of the line is not included in the string literal. However, if the next line begins with \\ then a newline is appended and the string literal continues.

  1. const hello_world_in_c =
  2. \\#include <stdio.h>
  3. \\
  4. \\int main(int argc, char **argv) {
  5. \\ printf("hello world\n");
  6. \\ return 0;
  7. \\}
  8. ;

See also:

Assignment

Use the const keyword to assign a value to an identifier:

test.zig

  1. const x = 1234;
  2. fn foo() void {
  3. // It works at global scope as well as inside functions.
  4. const y = 5678;
  5. // Once assigned, an identifier cannot be changed.
  6. y += 1;
  7. }
  8. test "assignment" {
  9. foo();
  10. }
  1. $ zig test test.zig
  2. ./docgen_tmp/test.zig:8:7: error: cannot assign to constant
  3. y += 1;
  4. ^

const applies to all of the bytes that the identifier immediately addresses. Pointers have their own const-ness.

If you need a variable that you can modify, use the var keyword:

test.zig

  1. const expect = @import("std").testing.expect;
  2. test "var" {
  3. var y: i32 = 5678;
  4. y += 1;
  5. expect(y == 5679);
  6. }
  1. $ zig test test.zig
  2. 1/1 test "var"... OK
  3. All 1 tests passed.

Variables must be initialized:

test.zig

  1. test "initialization" {
  2. var x: i32;
  3. x = 1;
  4. }
  1. $ zig test test.zig
  2. ./docgen_tmp/test.zig:2:5: error: variables must be initialized
  3. var x: i32;
  4. ^

undefined

Use undefined to leave variables uninitialized:

test.zig

  1. const expect = @import("std").testing.expect;
  2. test "init with undefined" {
  3. var x: i32 = undefined;
  4. x = 1;
  5. expect(x == 1);
  6. }
  1. $ zig test test.zig
  2. 1/1 test "init with undefined"... OK
  3. All 1 tests passed.

undefined can be coerced to any type. Once this happens, it is no longer possible to detect that the value is undefined. undefined means the value could be anything, even something that is nonsense according to the type. Translated into English, undefined means “Not a meaningful value. Using this value would be a bug. The value will be unused, or overwritten before being used.”

In Debug mode, Zig writes 0xaa bytes to undefined memory. This is to catch bugs early, and to help detect use of undefined memory in a debugger.