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
varare 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
}
YouTip