2020-11-25
*val
is a pointer to val
.val.*
is dereferencing val
;Print formatting:
"{}"
will print string value."{x}"
will print hex value."{b}"
will print binary value.@<identifier>
is a built-in.
@compileLog(@TypeOf(val))
will output the type name of val
.
!
is result (error_type!success_type) where !success_type alone infers the
error.
If a function doesn't (possibly) return an error then the !
is redundant.
To run project: zig make run
, to build: zig make build
_
will dispose of the value (like let _
binding in Rust)_
will dispose of
the value (like let _
binding in Rust)
switch
can only match on values known at compile time
|n|
is called a capture
Example also contains enum.
const MyEnum = enum {
A,
B,
C,
}
pub fn main() !void {
const val = MyEnum.A;
switch (val) {
MyEnum.A => {},
MyEnum.B => {},
else => |probably_c| {
}
}
}
comptime_int
: example const value: comptime_int = 5;
The main use case of comptime_int
is type inference.
const
.Defining your own error type is similar to an enum.
const MyError = error {
ErrorVariantA,
ErrorVariantB,
}
Using errors:
fn throw() MyError!void {
return error.ErrorVariantB;
}
Dealing with errors:
function_that_generates_errors() catch |err| switch (err) {
error.ErrorVariantA => {},
error.ErrorVariantB => {}
}
Can be represented as a numerical value using @enumToInt
as long the as
enum is defined as enum(some_int_type)
.
Assigning a numerical value to a variant means the next variant will have the numerical value + 1. It is not necessary to assign a value higher than the previous value of the previous variant.
const EnumA = enum {
A,
B,
}
// We can also represent enums as u8
const EnumB = enum(u8) {
A, // <- 0
B // <- 1
}
const EnumC = enum(u8) {
A = 100,// <- 100
B, // <- 101
C, // <- 102
D = 1, // <- 1
E, // <- 2
}
var value: EnumB = .B;
var byte = @enumToInt(value); // u8 is inferred
Prefix a type with ?
makes it into an optional.
var number: ?usize = null;
Using orelse
we can do an early return or assign a defaut value;
Default value:
var nullable: ?u8 = null;
var not_null = nullable orelse 0;
Early return:
var nullable: ?u8 = null;
var not_null = nullable orelse return;
String literals = const [N;0]u8
.
String literals are pointers to arrays. String literals live in ro memory.
const string = "hello"; // *const [5:0]u8;
String literals can coerce into []const u8
(from *const [L:0]u8
).
Note: [Len;0]
where zero means null terminated.
String literal to byte array is done via coercion:
const string = "hello";
const byte_arr: []const u8 = string;
var arr = [_]u8{1, 2, 3};
var slice: []const u8 = &arr;
var alt_array: [2]u8 = .{1, 2};
Notes on struct declaration:
var
/ const
should be terminated with semicolon,
whereas fields should have a comma.
const AStruct = struct {
const Self = @Type(); // semicolon because it's not a field
val: u32,
}
var inst = AStruct { val = 213 };
Anonymous structs:
const variable_name = .{ field_name: u32 = 123 };
const nameless = .{4,8};
var value = nameless.@"0"; // = 4
var other_value = nameless[1]; // = 8
TODO: needs more info
const PackyStruct = packed struct {
a: u2,
b: u2,
c: u2,
d: u2,
};
A union has to be tagged (union(enum)
as opposed to just union
)
to be able to use with a switch statement.
// Only one value
const SomeUnion = union {
A: u16,
B: [2]u8,
}
// Can switch on an instance of this
const Taggy = union(enum) {
A: u16
B: [2]u8
}
Creating a module is a case of adding a file and importing said file:
// mymod.zig
pub const VALUE: u32 = 1;
// main.zig
const module_name = @import("mymod.zig");
const other_module = @import("dir/mymod.zig");
pub fn main() void {
const value = module_name.VALUE;
}
Using an external Rust libary:
Modify the build.zig and call the following functions
on the exe
object:
// main.zig
extern fn greet() void;
pub fn main() anyerror!void {
greet();
}
// build.zig
const exe = b.addExecutable("ffibits", "src/main.zig");
//... Everything else
exe.linkSystemLibrary("c"); // Includes libc
exe.linkSystemLibrary("myname"); // Name of the library
exe.addLibPath("./myname/target/release/"); // Add the path to where the library is
// ...
exe.install();
This code makes the assumption that there will be a file in "./myname/target/release/" named "libmyname.so" or "libmyname.a" (on linux)
NOTE: At the time of writing there is presumably a bug: When rebuilding the library it isn't updated in the Zig code until you touch some of the Zig code using it.
Optionally one can omit exe.linkSystemLibrary("myname");
if you change:
extern fn greet() void;
to
extern "myname" fn greet() void;