# Structs, Methods and Namespaces — Zig

Source: https://www.geekswithgeeks.com/en/zig/t-structs

> Define structs with default values, methods and declarations.

## Structs are also namespaces

A **struct** groups fields: `const Item = struct { sku: []const u8, qty: u32 = 1 };`, with optional **default values**. Instances are created with **struct literals** (`.{ .sku = "pen", .qty = 2 }`), where the leading dot lets the compiler infer the type from context. Functions declared inside a struct are **methods** when their first parameter is the struct type or a pointer to it, and can be called with dot syntax: `item.total()` is sugar for `Item.total(item)`. Use `self: Item` (a copy, read-only) or `self: *Item` (to modify). **`@This()`** refers to the enclosing type, useful in generic code. Structs also hold **declarations** (constants, nested types, functions), so a struct doubles as a **namespace**, and every Zig **source file is itself a struct** whose public (`pub`) declarations can be imported with `@import`. A common convention is an `init` function returning a configured instance and a `deinit` method that releases resources. **Anonymous struct literals** and **tuples** (`.{ 1, "two" }`) are used for format arguments and multiple return values.

## A struct with fields and declarations

Fields hold per-instance data; declarations such as methods and constants belong to the type.

![A box split into an upper area with field slots and a lower area with function and constant icons, labelled as shared by all instances.](assets/figures/zig/section-3-map.svg) — Figure 3.1 — Fields and declarations in a struct.

## An invoice struct with methods

Default values, methods with self and a namespaced constant.

```zig
const std = @import("std");

const LineItem = struct {
    sku: []const u8,
    price_paise: u32,
    qty: u32 = 1,                                  // default value

    fn total(self: LineItem) u64 {
        return @as(u64, self.price_paise) * self.qty;
    }
};

const Invoice = struct {
    number: u32,
    items: []const LineItem,
    paid: bool = false,

    pub const gst_percent: u64 = 18;               // a declaration, shared by all invoices

    pub fn subtotal(self: Invoice) u64 {
        var sum: u64 = 0;
        for (self.items) |item| sum += item.total();
        return sum;
    }

    pub fn grandTotal(self: Invoice) u64 {
        const s = self.subtotal();
        return s + (s * gst_percent + 50) / 100;   // round to nearest paisa
    }

    pub fn markPaid(self: *Invoice) void {         // pointer receiver: modifies the invoice
        self.paid = true;
    }
};

pub fn main() void {
    const items = [_]LineItem{
        .{ .sku = "pen", .price_paise = 4_950, .qty = 2 },
        .{ .sku = "ink", .price_paise = 19_900 },   // qty defaults to 1
    };
    var inv = Invoice{ .number = 7, .items = &items };
    inv.markPaid();
    std.debug.print("INV-{d}: subtotal {d}, total {d}, paid {}\n", .{ inv.number, inv.subtotal(), inv.grandTotal(), inv.paid });
}
```

## Files are structs

Because each file is a struct, `const invoice = @import("invoice.zig");` gives you a namespace whose `pub` declarations you can use as `invoice.Invoice` or `invoice.parse`. Non-pub declarations stay private to the file.

**Quiz:** What does `inv.markPaid()` desugar to when markPaid takes `self: *Invoice`?

- [x] Invoice.markPaid(&inv), passing a pointer
- [ ] Invoice.markPaid(inv) with a copy
- [ ] A virtual method call
- [ ] It is a compile error

*Answer:* Invoice.markPaid(&inv), passing a pointer. Method call syntax passes the address automatically when the parameter is a pointer.
