Variables

A variable is a unit of Memory storage.

Variables are never allowed to shadow identifiers from an outer scope.

It is generally preferable to use const rather than var when declaring a variable. This causes less work for both humans and computers to do when reading code, and creates more optimization opportunities.

Container Level Variables

Container level variables have static lifetime and are order-independent and lazily analyzed. The initialization value of container level variables is implicitly comptime. If a container level variable is const then its value is comptime-known, otherwise it is runtime-known.

container_level_variables.zig

  1. var y: i32 = add(10, x);
  2. const x: i32 = add(12, 34);
  3. test "container level variables" {
  4. try expect(x == 46);
  5. try expect(y == 56);
  6. }
  7. fn add(a: i32, b: i32) i32 {
  8. return a + b;
  9. }
  10. const std = @import("std");
  11. const expect = std.testing.expect;

Shell

  1. $ zig test container_level_variables.zig
  2. 1/1 test "container level variables"... OK
  3. All 1 tests passed.

Container level variables may be declared inside a struct, union, or enum:

namespaced_container_level_variable.zig

  1. const std = @import("std");
  2. const expect = std.testing.expect;
  3. test "namespaced container level variable" {
  4. try expect(foo() == 1235);
  5. try expect(foo() == 1236);
  6. }
  7. const S = struct {
  8. var x: i32 = 1234;
  9. };
  10. fn foo() i32 {
  11. S.x += 1;
  12. return S.x;
  13. }

Shell

  1. $ zig test namespaced_container_level_variable.zig
  2. 1/1 test "namespaced container level variable"... OK
  3. All 1 tests passed.

Static Local Variables

It is also possible to have local variables with static lifetime by using containers inside functions.

static_local_variable.zig

  1. const std = @import("std");
  2. const expect = std.testing.expect;
  3. test "static local variable" {
  4. try expect(foo() == 1235);
  5. try expect(foo() == 1236);
  6. }
  7. fn foo() i32 {
  8. const S = struct {
  9. var x: i32 = 1234;
  10. };
  11. S.x += 1;
  12. return S.x;
  13. }

Shell

  1. $ zig test static_local_variable.zig
  2. 1/1 test "static local variable"... OK
  3. All 1 tests passed.

The extern keyword or @extern builtin function can be used to link against a variable that is exported from another object. The export keyword or @export builtin function can be used to make a variable available to other objects at link time. In both cases, the type of the variable must be C ABI compatible.

See also:

Thread Local Variables

A variable may be specified to be a thread-local variable using the threadlocal keyword:

tls.zig

  1. const std = @import("std");
  2. const assert = std.debug.assert;
  3. threadlocal var x: i32 = 1234;
  4. test "thread local storage" {
  5. const thread1 = try std.Thread.spawn(.{}, testTls, .{});
  6. const thread2 = try std.Thread.spawn(.{}, testTls, .{});
  7. testTls();
  8. thread1.join();
  9. thread2.join();
  10. }
  11. fn testTls() void {
  12. assert(x == 1234);
  13. x += 1;
  14. assert(x == 1235);
  15. }

Shell

  1. $ zig test tls.zig
  2. 1/1 test "thread local storage"... OK
  3. All 1 tests passed.

For Single Threaded Builds, all thread local variables are treated as regular Container Level Variables.

Thread local variables may not be const.

Local Variables

Local variables occur inside Functions, comptime blocks, and @cImport blocks.

When a local variable is const, it means that after initialization, the variable’s value will not change. If the initialization value of a const variable is comptime-known, then the variable is also comptime-known.

A local variable may be qualified with the comptime keyword. This causes the variable’s value to be comptime-known, and all loads and stores of the variable to happen during semantic analysis of the program, rather than at runtime. All variables declared in a comptime expression are implicitly comptime variables.

comptime_vars.zig

  1. const std = @import("std");
  2. const expect = std.testing.expect;
  3. test "comptime vars" {
  4. var x: i32 = 1;
  5. comptime var y: i32 = 1;
  6. x += 1;
  7. y += 1;
  8. try expect(x == 2);
  9. try expect(y == 2);
  10. if (y != 2) {
  11. // This compile error never triggers because y is a comptime variable,
  12. // and so `y != 2` is a comptime value, and this if is statically evaluated.
  13. @compileError("wrong y value");
  14. }
  15. }

Shell

  1. $ zig test comptime_vars.zig
  2. 1/1 test "comptime vars"... OK
  3. All 1 tests passed.