Zig Variables and Constants

In the Zig language, variables are containers for storing data.

In Zig, the definition and use of variables are very intuitive and powerful.

This article will detail how to define and use variables in Zig, including constants, variables, type inference, scope, and other aspects.

In Zig, constants are defined using theconstkeyword, while variables are defined using thevarkeyword.


Variables

In Zig, variables are defined using thevarkeyword.

Variables must have their type explicitly specified at definition, or the compiler can infer the type from the initialization value.

Variable Declaration

In Zig, variable declaration requires specifying a type. The syntax for variable declaration is as follows:

var variable_name: type = value;

variable_nameis the variable name,typeis the type,valueis the variable value.

For example:

var x: i32 = 42; // 定义一个 i32 类型的变量 x,初始值为 42
var y = 10;      // 编译器推断 y 的类型为 comptime_int

The value of a variable can be modified during program execution:

Example

const std = @import("std");

pub fn main() void {
    var b: i32 = 20; // Define an integer variable b with an initial value of 20
    b = 30; // Modify the value of variable b
    std.debug.print("b: {}\n", .{b});
}

Variable Characteristics

1. The type must be explicit:

  • Zig is a strongly typed language. The type of a variable must be explicitly specified at definition, or inferred from the initialization value.

  • If there is no initialization value, the type must be explicitly specified.

Example

var x: i32 = 10; // Explicitly specify the type
var y = 20;      // The compiler infers the type as comptime_int

2. Mutability:

  • Variables defined using thevarkeyword are mutable, and their values can be modified in subsequent code.

Example

var x: i32 = 10;
x = 20; // Modify the value of x

3. Scope:

  • The scope of a variable is block scope, meaning it is valid within the code block where it is defined.

Example

{
    var x: i32 = 10;
    std.debug.print("x = {}\n", .{x}); // Output: x = 10
}
// Here x is out of scope and cannot be accessed

4. Uninitialized variables:

  • Zig does not allow the use of uninitialized variables. If a variable is uninitialized, the compiler will report an error.

Example

var x: i32; // Error: variable x is not initialized
x = 10;    // Must be initialized first

Variable Types

Zig supports multiple data types, including but not limited to:

  • Basic types: integers (i32, i64etc.), unsigned integers (u32, u64etc.), floating-point numbers (f32, f64etc.), booleans (bool), characters (char)。
  • Composite types: arrays ([]T), structs (struct), enums (enum), unions (union), tuples ([]const T)。
  • Pointers and references: pointers (*T), references (&T), optional types (?T)。
  • Function types:fn(...) -> R。

Variable Naming Rules

Zig variable naming follows some basic rules, including:

  • Variable names must begin with a letter or an underscore.

  • Variable names can contain letters, digits, and underscores.

  • Variable names are case-sensitive.

  • Variable names cannot be Zig keywords (such asvar、const、fnetc.).

Example

var my_var: i32 = 10; // Legal variable name
var _value: f64 = 3.14; // Legal variable name
var 1var: i32 = 10; // Illegal variable name

Type Inference

Zig supports type inference. If a variable is initialized at definition, the compiler can infer the variable's type from the initial value.

Example

var x = 10;      // The compiler infers the type of x as comptime_int
var y = 3.14;    // The compiler infers the type of y as comptime_float
var z = "Hello"; // The compiler infers the type of z as *const [5:0]u8

Scope

The scope of a variable is determined by where it is defined.

In Zig, variables can be defined in global scope, local scope, and block scope.

Global Scope- Global variables can be accessed anywhere in the program.

Example

const std = @import("std");

const g: i32 = 90; // Global constant

pub fn main() void {
    std.debug.print("g: {}\n", .{g});
}

Local Scope- Local variables can only be accessed within the function or code block where they are defined.

Example

const std = @import("std");

pub fn main() void {
    var h: i32 = 100; // Local variable
    {
        var i: i32 = 110; // Block scope variable
        std.debug.print("i: {}\n", .{i});
    }
    // std.debug.print("i: {}\n", .{i}); // This line of code will cause a compilation error because i is not in the scope of the main function
    std.debug.print("h: {}\n", .{h});
}

Type Conversion

Zig provides type conversion functions to convert one type to another.

Example

const std = @import("std");

pub fn main() void {
    const j: i32 = 120;
    const k: f64 = @intToFloat(f64, j); // Convert integer j to floating-point number k
    std.debug.print("j: {}, k: {}\n", .{j, k});
}

Default Values

Variables must be initialized at definition, otherwise it will cause a compilation error.

Zig does not allow the use of uninitialized variables.

Example

const std = @import("std");

pub fn main() void {
    var l: i32 = 0; // Initialize variable l
    std.debug.print("l: {}\n", .{l});
}

Examples of Variable Usage

The following is a complete Zig program that demonstrates the definition and use of variables:

Example

const std = @import("std");

pub fn main() void {
    // Define variable
    var x: i32 = 10;
    var y = 20; // Type inferred as comptime_int

    // Modify the value of the variable
    x = 30;
    y = 40;

    // Output the value of the variable
    std.debug.print("x = {}\n", .{x}); // Output: x = 30
    std.debug.print("y = {}\n", .{y}); // Output: y = 40

    // Block-level scope
    {
        var z: i32 = 50;
        std.debug.print("z = {}\n", .{z}); // Output: z = 50
    }
    // Here z is out of scope and cannot be accessed
}

Constants

In Zig, constants are defined using theconstkeyword.

Once a constant is defined, its value cannot be changed.

Example

const std = @import("std");

pub fn main() void {
    const a: i32 = 10; // Define an integer constant a with a value of 10
    std.debug.print("a: {}\n", .{a});
}

Characteristics of Constants:

  • Immutability: The value of a constant cannot be modified after definition.

  • Determined at compile time: The value of a constant must be determined at compile time and cannot be the result of runtime computation.

  • Type inference: If the type of a constant is not explicitly specified, the compiler will infer the type from the initial value.

  • Naming convention: Constants are usually named using all uppercase letters and underscores (such asMAX_SIZE) to distinguish them from variables.


Compile-Time Constants

Zig supports compile-time constants (comptime constants). The values of these constants are computed at compile time and can be used for compile-time logic.

Defining Compile-Time Constants

Use the comptime keyword to define compile-time constants.

Syntax:

comptime const constant_name: type = value;

For example:

comptime const MAX_SIZE: usize = 100; // 编译时常量

Characteristics

  • Compile-time computation:The values of compile-time constants are computed at compile time and can be used for compile-time logic (such as array sizes, type computations, etc.).
  • Type safety:The type of a compile-time constant must be determined at compile time.
  • Performance optimization:Using compile-time constants can avoid runtime computation overhead.

Example

const std = @import("std");

pub fn main() void {
    comptime const SIZE: usize = 10; // Compile-time constant
    var arr: [SIZE]i32 = undefined;  // Use a compile-time constant to define array size
    std.debug.print("Array size = {}\n", .{SIZE}); // Output: Array size = 10
}

Differences Between Variables and Constants

FeatureVariable (var)Constant (const)Compile-time constant (comptime const)
MutabilityMutableImmutableImmutable
Definition keywordvarconstcomptime const
Initialization requirementMust be initializedMust be initializedMust be initialized
Type inferenceSupportedSupportedSupported
ScopeBlock scopeBlock scopeBlock scope
Usage scenariosValues that need modificationValues that don't need modificationValues computed at compile time

Example

const std = @import("std");

pub fn main() void {
    // variable
    var x: i32 = 10;
    x = 20;
    std.debug.print("x = {}\n", .{x}); // Output: x = 20

    // constant
    const PI: f64 = 3.14159;
    std.debug.print("PI = {}\n", .{PI}); // Output: PI = 3.14159

    // compile-time constant
    comptime const SIZE: usize = 5;
    var arr: [SIZE]i32 = undefined;
    std.debug.print("Array size = {}\n", .{SIZE}); // Output: Array size = 5
}
Other extensions