YouTip LogoYouTip

Zig Var Const

Zig Variables and Constants | Rookie Tutorial

In the Zig language, variables are containers that store data.

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

This article details how to define and use variables in Zig, including constants, variables, type inference, scope, and more.

In Zig, constants are defined using the const keyword, while variables are defined using the var keyword.


Variables

In Zig, variables are defined using the var keyword.

A variable must have its type explicitly specified at definition, or let the compiler infer the type through its initial value.

Variable Declaration

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

var variable_name: type = value;

variable_name is the name of the variable, type is the type, and value is the variable's value.

For example:

var x: i32 = 42; // Define a variable x of type i32 with an initial value of 42
var y = 10; // The compiler infers y's type as 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. Type must be explicit:

  • Zig is a strongly typed language. The type of a variable must be explicitly specified at definition or inferred through the initial value.
  • If there is no initial value, the type must be explicitly specified.

Example

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

2. Mutability:

  • Variables defined with var 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-level scope, meaning it is valid only within the code block where it is defined.

Example

{
    var x: i32 = 10;
    std.debug.print("x = {}n", .{x}); // Output: x = 10
}
// x is out of scope here 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 uninitialized
x = 10; // Must be initialized first

Variable Types

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

  • Basic types: integers (i32, i64, etc.), unsigned integers (u32, u64, etc.), floating-point numbers (f32, f64, etc.), 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 start with a letter or an underscore.
  • Variable names can contain letters, numbers, and underscores.
  • Variable names are case-sensitive.
  • Variable names cannot be Zig keywords (such as var, const, fn, etc.).

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 based on the initial value.

Example

var x = 10; // Compiler infers x's type as comptime_int
var y = 3.14; // Compiler infers y's type as comptime_float
var z = "Hello"; // Compiler infers z's type as *const [5:0]u8

Scope

The scope of a variable is determined by its definition location.

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 would 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 when defined, 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});
}

Variable Usage Example

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

Example

const std = @import("std");

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

    // Modify variable values
    x = 30;
    y = 40;

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

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

Constants

In Zig, constants are defined using the const keyword.

Once defined, the value of a constant 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});
}

Constant Characteristics:

  • Immutability: The value of a constant cannot be modified after definition.
  • Compile-time Determination: The value of a constant must be determined at compile time and cannot be the result of runtime calculation.
  • Type Inference: If the type of a constant is not explicitly specified, the compiler infers the type based on the initial value.
  • Naming Convention: Constants are usually named using all uppercase letters and underscores (e.g., MAX_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 in 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; // Compile-time constant

Characteristics

  • Compile-Time Calculation: The value of a compile-time constant is calculated at compile time and can be used in compile-time logic (such as array size, type calculations, 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 calculation overhead.

Example

const std = @import("std");

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

Differences Between Variables and Constants

Feature Variable (var) Constant (const) Compile-Time Constant (comptime const)
Mutability Mutable Immutable Immutable
Definition Keyword var const comptime const
Initialization Requirement Must be initialized Must be initialized Must be initialized
Type Inference Supported Supported Supported
Scope Block-level scope Block-level scope Block-level scope
Usage Scenario Values that need modification Values that do not need modification Values 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: i32 = undefined;
    std.debug.print("Array size = {}n", .{SIZE}); // Output: Array size = 5
}
← Zig IfZig Comments β†’