Structs
Basic Struct Declaration
Structs in Zig are declared with explicit field types:
const expect = @import ( "std" ). testing . expect ;
// Declare a struct.
// Zig gives no guarantees about the order of fields and the size of
// the struct but the fields are guaranteed to be ABI-aligned.
const Point = struct {
x : f32 ,
y : f32 ,
};
// Declare an instance of a struct.
const p : Point = .{
. x = 0.12 ,
. y = 0.34 ,
};
Struct fields are ABI-aligned, but field order and struct size are not guaranteed unless using packed struct or extern struct.
Struct Methods
Structs can have functions in their namespace:
const Vec3 = struct {
x : f32 ,
y : f32 ,
z : f32 ,
pub fn init ( x : f32 , y : f32 , z : f32 ) Vec3 {
return Vec3 {
. x = x ,
. y = y ,
. z = z ,
};
}
pub fn dot ( self : Vec3 , other : Vec3 ) f32 {
return self . x * other . x + self . y * other . y + self . z * other . z ;
}
};
test "dot product" {
const v1 = Vec3 . init ( 1.0 , 0.0 , 0.0 );
const v2 = Vec3 . init ( 0.0 , 1.0 , 0.0 );
try expect ( v1 . dot ( v2 ) == 0.0 );
// Other than being available to call with dot syntax, struct methods are
// not special. You can reference them as any other declaration inside
// the struct:
try expect ( Vec3 . dot ( v1 , v2 ) == 0.0 );
}
Struct methods are just namespaced functions. The first parameter is conventionally named self.
Struct Declarations
Structs can contain constants and other declarations:
// Structs can have declarations.
// Structs can have 0 fields.
const Empty = struct {
pub const PI = 3.14 ;
};
test "struct namespaced variable" {
try expect ( Empty . PI == 3.14 );
try expect ( @sizeOf ( Empty ) == 0 );
// Empty structs can be instantiated the same as usual.
const does_nothing : Empty = .{};
_ = does_nothing ;
}
Default Field Values
Struct fields can have default values:
const Foo = struct {
a : i32 = 1234 ,
b : i32 ,
};
test "default struct initialization fields" {
const x : Foo = .{
. b = 5 ,
};
if ( x . a + x . b != 1239 ) {
comptime unreachable ;
}
}
Field Parent Pointer
You can compute a base pointer from a field pointer:
fn setYBasedOnX ( x : * f32 , y : f32 ) void {
const point : * Point = @fieldParentPtr ( "x" , x );
point . y = y ;
}
test "field parent pointer" {
var point = Point {
. x = 0.1234 ,
. y = 0.5678 ,
};
setYBasedOnX ( & point . x , 0.9 );
try expect ( point . y == 0.9 );
}
Generic Structs
Structs can be returned from functions to create generic types:
fn LinkedList ( comptime T : type ) type {
return struct {
pub const Node = struct {
prev : ?* Node ,
next : ?* Node ,
data : T ,
};
first : ?* Node ,
last : ?* Node ,
len : usize ,
};
}
test "linked list" {
// Functions called at compile-time are memoized.
try expect ( LinkedList ( i32 ) == LinkedList ( i32 ));
const list = LinkedList ( i32 ){
. first = null ,
. last = null ,
. len = 0 ,
};
try expect ( list . len == 0 );
// Since types are first class values you can instantiate the type
// by assigning it to a variable:
const ListOfInts = LinkedList ( i32 );
try expect ( ListOfInts == LinkedList ( i32 ));
var node = ListOfInts . Node {
. prev = null ,
. next = null ,
. data = 1234 ,
};
const list2 = LinkedList ( i32 ){
. first = & node ,
. last = & node ,
. len = 1 ,
};
// When using a pointer to a struct, fields can be accessed directly,
// without explicitly dereferencing the pointer.
try expect ( list2 . first . ? . data == 1234 );
}
Generic structs in Zig are created at compile-time and are memoized, so List(i32) always refers to the same type.
Enums
Basic Enum Declaration
const expect = @import ( "std" ). testing . expect ;
const mem = @import ( "std" ). mem ;
// Declare an enum.
const Type = enum {
ok ,
not_ok ,
};
// Declare a specific enum field.
const c = Type . ok ;
Enum with Tag Type
You can specify the underlying integer type:
const Value = enum ( u2 ) {
zero ,
one ,
two ,
};
test "enum ordinal value" {
try expect ( @intFromEnum ( Value . zero ) == 0 );
try expect ( @intFromEnum ( Value . one ) == 1 );
try expect ( @intFromEnum ( Value . two ) == 2 );
}
Custom Ordinal Values
Override the ordinal value for enum fields:
const Value2 = enum ( u32 ) {
hundred = 100 ,
thousand = 1000 ,
million = 1000000 ,
};
test "set enum ordinal value" {
try expect ( @intFromEnum ( Value2 . hundred ) == 100 );
try expect ( @intFromEnum ( Value2 . thousand ) == 1000 );
try expect ( @intFromEnum ( Value2 . million ) == 1000000 );
}
// You can also override only some values.
const Value3 = enum ( u4 ) {
a ,
b = 8 ,
c ,
d = 4 ,
e ,
};
test "enum implicit ordinal values and overridden values" {
try expect ( @intFromEnum ( Value3 . a ) == 0 );
try expect ( @intFromEnum ( Value3 . b ) == 8 );
try expect ( @intFromEnum ( Value3 . c ) == 9 );
try expect ( @intFromEnum ( Value3 . d ) == 4 );
try expect ( @intFromEnum ( Value3 . e ) == 5 );
}
When overriding some ordinal values, subsequent values continue from the last explicit value.
Enum Methods
Enums can have methods just like structs:
const Suit = enum {
clubs ,
spades ,
diamonds ,
hearts ,
pub fn isClubs ( self : Suit ) bool {
return self == Suit . clubs ;
}
};
test "enum method" {
const p = Suit . spades ;
try expect ( ! p . isClubs ());
}
Switching on Enums
Enums work naturally with switch expressions:
const Foo = enum {
string ,
number ,
none ,
};
test "enum switch" {
const p = Foo . number ;
const what_is_it = switch ( p ) {
Foo . string => "this is a string" ,
Foo . number => "this is a number" ,
Foo . none => "this is a none" ,
};
try expect ( mem . eql ( u8 , what_is_it , "this is a number" ));
}
switch ( my_enum ) {
. option1 => {},
. option2 => {},
. option3 => {},
// Must handle all cases
}
switch ( my_enum ) {
. option1 => {},
. option2 => {},
else => {}, // Handle remaining cases
}
Enum Introspection
Getting Tag Type
const Small = enum {
one ,
two ,
three ,
four ,
};
test "std.meta.Tag" {
try expect ( @typeInfo ( Small ). @"enum" . tag_type == u2 );
}
test "@typeInfo" {
try expect ( @typeInfo ( Small ). @"enum" . fields . len == 4 );
try expect ( mem . eql ( u8 , @typeInfo ( Small ). @"enum" . fields [ 1 ]. name , "two" ));
}
Tag Name
test "@tagName" {
try expect ( mem . eql ( u8 , @tagName ( Small . three ), "three" ));
}
Basic Struct
Generic Struct
Basic Enum
Enum with Values
const Point = struct {
x : f32 ,
y : f32 ,
};