From ee9b8fc921f48dc893808e1c9dbfbef321aa362c Mon Sep 17 00:00:00 2001 From: Nguyễn Gia Phong Date: Sun, 28 Feb 2021 17:18:03 +0700 Subject: [lang/zig] Learn some Zig --- lang/zig/fn.zig | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 lang/zig/fn.zig (limited to 'lang/zig/fn.zig') diff --git a/lang/zig/fn.zig b/lang/zig/fn.zig new file mode 100644 index 0000000..0fb3002 --- /dev/null +++ b/lang/zig/fn.zig @@ -0,0 +1,78 @@ +const expect = @import("std").testing.expect; + +// Functions are declared like this +fn add(a: i8, b: i8) i8 { + return if (a == 0) b else a + b; +} + +// The export specifier makes a function externally visible in the generated +// object file, and makes it use the C ABI. +export fn sub(a: i8, b: i8) i8 { return a - b; } + +// The extern specifier is used to declare a function that will be resolved +// at link time, when linking statically, or at runtime, when linking +// dynamically. +extern "c" fn atan2(a: f64, b: f64) f64; + +// The @setCold builtin tells the optimizer that a function is rarely called. +fn abort() noreturn { + @setCold(true); + while (true) {} +} + +// The naked calling convention makes a function not have any function prologue +// or epilogue. This can be useful when integrating with assembly. +fn _start() callconv(.Naked) noreturn { + abort(); +} + +// The inline specifier forces a function to be inlined at all call sites. +// If the function cannot be inlined, it is a compile-time error. +inline fn shiftLeftOne(a: u32) u32 { + return a << 1; +} + +// The pub specifier allows the function to be visible when importing. +// Another file can use @import and call sub2 +pub fn sub2(a: i8, b: i8) i8 { return a - b; } + +// Functions can be used as values and are equivalent to pointers. +fn do_op(fn_call: fn (a: i8, b: i8) i8, op1: i8, op2: i8) i8 { + return fn_call(op1, op2); +} + +test "function" { + expect(do_op(add, 5, 6) == 11); + expect(do_op(sub2, 5, 6) == -1); +} + +const Point = struct { x: i32, y: i32 }; + +fn foo(point: Point) i32 { + // Here, `point` could be a reference, or a copy. The function body + // can ignore the difference and treat it as a value. Be very careful + // taking the address of the parameter - it should be treated as if + // the address will become invalid when the function returns. + return point.x + point.y; +} + +test "pass struct to function" { + expect(foo(Point{ .x = 1, .y = 2 }) == 3); +} + +fn addFortyTwo(x: anytype) @TypeOf(x) { + return x + 42; +} + +test "fn type inference" { + expect(addFortyTwo(1) == 43); + expect(@TypeOf(addFortyTwo(1)) == comptime_int); + const y: i64 = 2; + expect(addFortyTwo(y) == 44); + expect(@TypeOf(addFortyTwo(y)) == i64); +} + +test "fn reflection" { + expect(@typeInfo(@TypeOf(expect)).Fn.return_type.? == void); + expect(@typeInfo(@TypeOf(expect)).Fn.is_var_args == false); +} -- cgit 1.4.1