Skip to content

Instantly share code, notes, and snippets.

@rapando
Created October 23, 2022 14:11
Show Gist options
  • Save rapando/eff56ef975829b77cedb869ced1b53ca to your computer and use it in GitHub Desktop.
Save rapando/eff56ef975829b77cedb869ced1b53ca to your computer and use it in GitHub Desktop.
Zig Learning
const std = @import("std");
const eq1 = std.mem.eql;
const ArrayList = std.ArrayList;
const test_allocator = std.testing.allocator;
// struct definition
const Person = struct {
x: f64,
y: f64,
};
// struct elements can have default values,
// structs can also be anonymous
const Coordinates = struct {
x: f64 = 34.00,
y: f64 = 0.50,
z: f64, // only z needs a value in declaring a new struct instance
fn print(self: *Coordinates) void {
std.debug.print("you are at ({},{},{})\n", .{ self.x, self.y, self.z });
}
};
// enums
const EnumType = enum {
One,
Two,
// Three = 3, // can't print this directly, has to be inferred
};
// error handling
const MyError = error{
GenericError, // just like enums
OtherError,
};
// using meta programming, you can create structs that take in a specified data type
fn Vec2Of(comptime T: type) type {
return struct { x: T, y: T };
}
const V2i64 = Vec2Of(i64);
const V2f64 = Vec2Of(f64);
// factory type for heap programming
const Gpa = std.heap.GeneralPurposeAllocator(.{});
pub fn main() void {
std.debug.print("Hello, {s}!\n", .{"World"});
const a: i32 = 5;
var b: u32 = 5000;
std.debug.print("a={d}, b={d}\n", .{ a, b });
// for explicit type coercion, use @
const inferred_constant = @as(i32, 5);
var inferred_variable = @as(u32, 5000);
std.debug.print("inferred_constant={d}, inferred_variable={d}\n", .{ inferred_constant, inferred_variable });
// you must define variables with a value. if not, use 'undefined'
const c: i32 = undefined;
var d: u32 = undefined;
std.debug.print("c={d}, d={d}\n", .{ c, d });
// arrays
var arr = [5]u8{ 'a', 'b', 'c', 'd', 'e' };
std.debug.print("array={}\n", .{arr[0]});
var arr_part: []u8 = arr[0..2];
std.debug.print("arr_part length {}\n", .{arr_part.len});
// std.debug.print("0..2 : {}\n\n", .{arr[0..2]});
foo();
std.debug.print("foo_int={}\n", .{foo_int()});
// to ignore the output
_ = foo_int();
func_with_params(a);
// structs
var person: Person = Person{
.x = 90.9,
.y = 80.5,
};
std.debug.print("person: {}\n", .{person});
var kenya: Coordinates = Coordinates{
.x = 0.56,
.z = 36,
};
std.debug.print("co-ordinates: {}\n", .{kenya});
kenya.print();
// this is a tuple, basically an anonymous struct {1,2}
// that's what we've been using in the print statement
// ---- enums
std.debug.print("enumOne: {}\n", .{EnumType.One});
std.debug.print("enumTwo: {}\n", .{EnumType.Two});
// std.debug.print("enumThree: {}\n", .{@enumToInt(EnumType.Three) == 3});
// --- control structures
var three: i32 = 2;
if (three == 3) {
std.debug.print("is three\n", .{});
} else {
std.debug.print("is not three\n", .{});
}
switch (three) {
0 => std.debug.print("is zero\n", .{}),
1 => std.debug.print("is two\n", .{}),
3 => std.debug.print("is three\n", .{}),
else => std.debug.print("is other\n", .{}),
}
// zig provides a for loop that only works on arrays and slices
var array = [_]i32{ 47, 48, 49 };
for (array) |value| {
std.debug.print("array: {}\n", .{value});
}
for (array) |value, index| {
std.debug.print("index:{}, value:{}\n", .{ index, value });
}
// while loop
var index: u32 = 0;
while (index < 2) {
std.debug.print("value: {}\n", .{array[index]});
index += 1;
}
// error handling
// catch traps and handles errors bubbling up
_ = error_handling(42) catch |err| {
std.debug.print("error : {}\n", .{err});
};
// pointers
var pointer_val: i32 = 90;
pointer_printer(&pointer_val);
// ------------- META PROGRAMMING
// types are valid values at compile time
// most runtime code will also work at compile time
// struct field evaluation at compile time duck-typed
// available tools for compile-type reflection
var meta_x: i64 = 47;
var meta_y: i32 = 47;
std.debug.print("i64-meta : {}\n", .{meta_programming(meta_x)});
std.debug.print("i32-meta : {}\n", .{meta_programming(meta_y)});
var v1 = V2i64{ .x = 47, .y = 47 };
var v2 = V2f64{ .x = 47, .y = 47 };
std.debug.print("v1={}\n v2={}\n\n", .{ v1, v2 });
// // --------------- THE HEAP
// // zig gives you options to interact with the heap
// // they all follow the same pattern
// // 1. create an allocator factory struct
// // 2. retrieve the std.mem.Allocator struct
// // 3. use the alloc/free and create/destroy functions to manipulate the heap
// // 4. (optional) deinit the Allocator factory
// var gpa = Gpa{}; // instantiate the factory
// var galloc = &gpa.allocator; // retrieve the created allocator.
// // scope lifetime of the allocator to this function and perform cleanup
// defer _ = &gpa.deinit();
// var slice = try galloc.alloc(i32, 2);
// // uncomment the following line to remove memory leak warning
// defer galloc.free(slice);
// var single = try galloc.create(i32);
// defer galloc.destroy(single);
// slice[0] = 47;
// slice[1] = 48;
// single.* = 49;
// std.debug.print("slice : [{},{}]\n", .{ slice[0], slice[1] });
// std.debug.print("single: {}\n", .{single.*});
}
pub fn foo() void {
std.debug.print("foo!\n", .{});
}
pub fn foo_int() i32 {
return 47;
}
pub fn func_with_params(x: i32) void {
std.debug.print("func_with_params={}\n", .{x});
}
// error handling
fn error_handling(v: i32) !i32 {
if (v == 42) return MyError.GenericError;
return v;
}
fn pointer_printer(value: *i32) void {
std.debug.print("pointer : {}\n", .{value});
std.debug.print("value : {}\n", .{value.*});
}
fn meta_programming(x: anytype) @TypeOf(x) {
// note that this if statement happens at compile time, not runtime.
if (@TypeOf(x) == i64) {
return x + 2;
} else {
return 2 * x;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment