1. 1/1 test "function"... OK
    2. All 1 tests passed.

    Function values are like pointers:

    test.zig

    1. const expect = @import("std").testing.expect;
    2. comptime {
    3. expect(@TypeOf(foo) == fn()void);
    4. expect(@sizeOf(fn()void) == @sizeOf(?fn()void));
    5. }
    6. fn foo() void { }

    Structs, unions, and arrays can sometimes be more efficiently passed as a reference, since a copy could be arbitrarily expensive depending on the size. When these types are passed as parameters, Zig may choose to copy and pass by value, or pass by reference, whichever way Zig decides will be faster. This is made possible, in part, by the fact that parameters are immutable.

    test.zig

    1. x: i32,
    2. y: i32,
    3. fn foo(point: Point) i32 {
    4. // Here, `point` could be a reference, or a copy. The function body
    5. // can ignore the difference and treat it as a value. Be very careful
    6. // taking the address of the parameter - it should be treated as if
    7. // the address will become invalid when the function returns.
    8. return point.x + point.y;
    9. }
    10. const expect = @import("std").testing.expect;
    11. expect(foo(Point{ .x = 1, .y = 2 }) == 3);
    1. $ zig test test.zig
    2. 1/1 test "pass struct to function"... OK
    3. All 1 tests passed.

    Function parameters can be declared with anytype in place of the type. In this case the parameter types will be inferred when the function is called. Use @TypeOf and to get information about the inferred type.

    test.zig

    1. $ zig test test.zig
    2. 1/1 test "fn type inference"... OK
    3. All 1 tests passed.
    1. const expect = @import("std").testing.expect;
    2. test "fn reflection" {
    3. expect(@typeInfo(@TypeOf(expect)).Fn.return_type.? == void);
    4. expect(@typeInfo(@TypeOf(expect)).Fn.is_var_args == false);
    5. }