# Struct Definitions

### Struct Definitions

A `struct` is a type that groups several values together.

You use a struct when one idea has several pieces of data. For example, a point has an `x` value and a `y` value. A user has an id, a name, and an email. A file entry has a path, a size, and a timestamp.

In Zig, a struct is written like this:

```zig
const Point = struct {
    x: i32,
    y: i32,
};
```

This defines a new type named `Point`.

The fields are:

```zig
x: i32
y: i32
```

Each field has a name and a type.

Now we can create a `Point` value:

```zig
const p = Point{
    .x = 10,
    .y = 20,
};
```

The field names start with a dot:

```zig
.x = 10
.y = 20
```

This style is explicit. When you read the code, you know exactly which value goes into which field.

#### Accessing Fields

You access struct fields with dot syntax:

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

const Point = struct {
    x: i32,
    y: i32,
};

pub fn main() void {
    const p = Point{
        .x = 10,
        .y = 20,
    };

    std.debug.print("x = {}, y = {}\n", .{ p.x, p.y });
}
```

Output:

```text
x = 10, y = 20
```

The expression `p.x` means “the `x` field of `p`.”

The expression `p.y` means “the `y` field of `p`.”

#### Structs Are Types

A struct definition creates a type.

This line:

```zig
const Point = struct {
    x: i32,
    y: i32,
};
```

means: create an anonymous struct type, then store that type in the constant `Point`.

That may sound strange at first, but it fits Zig’s model. Types are values that exist at compile time.

So `Point` is not a variable containing a point. It is the type itself.

This creates a value of that type:

```zig
const p = Point{
    .x = 10,
    .y = 20,
};
```

You can think of it like this:

```text
Point is the shape.
p is one actual value with that shape.
```

#### Mutable Struct Values

If you declare a struct value with `var`, you can change its fields:

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

const Counter = struct {
    value: i32,
};

pub fn main() void {
    var c = Counter{
        .value = 0,
    };

    c.value += 1;
    c.value += 1;

    std.debug.print("counter = {}\n", .{c.value});
}
```

Output:

```text
counter = 2
```

Because `c` is declared with `var`, its field can be changed.

If `c` were declared with `const`, this would fail:

```zig
const c = Counter{
    .value = 0,
};

c.value += 1; // error
```

A `const` struct value cannot be modified.

#### Field Order

Fields are usually written one per line:

```zig
const User = struct {
    id: u64,
    name: []const u8,
    email: []const u8,
};
```

When creating a struct value, you should normally use named fields:

```zig
const user = User{
    .id = 1,
    .name = "Ada",
    .email = "ada@example.com",
};
```

This is safer than relying on position. The code stays clear even when the struct has many fields.

Zig expects you to initialize all fields unless a field has a default value.

#### Default Field Values

A struct field can have a default value:

```zig
const Config = struct {
    port: u16 = 8080,
    debug: bool = false,
};
```

Now you can create a value without explicitly setting every field:

```zig
const config = Config{};
```

This uses the defaults:

```zig
port = 8080
debug = false
```

You can override one field and keep the other default:

```zig
const config = Config{
    .debug = true,
};
```

Now `debug` is `true`, but `port` is still `8080`.

Default values are useful for configuration structs and test data.

#### Empty Structs

A struct can have no fields:

```zig
const Empty = struct {};
```

This may look useless, but empty structs are sometimes useful for marker types, namespaces, and compile-time patterns.

For now, just know that it is legal.

#### Structs as Function Parameters

You can pass structs to functions:

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

const Point = struct {
    x: i32,
    y: i32,
};

fn printPoint(p: Point) void {
    std.debug.print("({}, {})\n", .{ p.x, p.y });
}

pub fn main() void {
    const p = Point{
        .x = 3,
        .y = 4,
    };

    printPoint(p);
}
```

Output:

```text
(3, 4)
```

The function parameter says:

```zig
p: Point
```

That means `p` must be a `Point`.

#### Returning Structs from Functions

A function can also return a struct:

```zig
const Point = struct {
    x: i32,
    y: i32,
};

fn origin() Point {
    return Point{
        .x = 0,
        .y = 0,
    };
}
```

This function returns a `Point` value.

You can use it like this:

```zig
const p = origin();
```

Structs are ordinary values. They can be stored, passed, returned, copied, and placed inside other structs.

#### Nested Structs

A struct can contain another struct:

```zig
const Point = struct {
    x: i32,
    y: i32,
};

const Rectangle = struct {
    top_left: Point,
    bottom_right: Point,
};
```

Now a rectangle is made of two points:

```zig
const rect = Rectangle{
    .top_left = Point{
        .x = 0,
        .y = 0,
    },
    .bottom_right = Point{
        .x = 100,
        .y = 50,
    },
};
```

You can access nested fields with repeated dot syntax:

```zig
const x = rect.top_left.x;
```

This means:

```text
take rect
then take its top_left field
then take that point's x field
```

#### Anonymous Struct Values

Zig can create anonymous struct values:

```zig
const person = .{
    .name = "Ada",
    .age = 36,
};
```

Here, we did not write a named type like `Person`. Zig infers an anonymous struct type from the fields.

This is useful in small local cases, especially for formatting arguments:

```zig
std.debug.print("{} {}\n", .{ "hello", 123 });
```

The expression `.{ "hello", 123 }` is an anonymous tuple-like struct.

For main data models, prefer named structs:

```zig
const Person = struct {
    name: []const u8,
    age: u8,
};
```

Named structs make your program easier to read.

#### Structs Can Contain Functions

A Zig struct can contain declarations, including functions:

```zig
const Point = struct {
    x: i32,
    y: i32,

    fn zero() Point {
        return Point{
            .x = 0,
            .y = 0,
        };
    }
};
```

Now `zero` belongs to the `Point` namespace:

```zig
const p = Point.zero();
```

This does not mean Zig has classes in the same way as Java or C++. A struct is still a data type. But a struct can also act as a namespace for functions related to that data.

We will study this more in the next section on struct methods.

#### Structs Are Often Used as Namespaces

Sometimes a struct is used only to group declarations:

```zig
const Math = struct {
    fn add(a: i32, b: i32) i32 {
        return a + b;
    }

    fn sub(a: i32, b: i32) i32 {
        return a - b;
    }
};
```

You can call these functions like this:

```zig
const x = Math.add(10, 5);
const y = Math.sub(10, 5);
```

Here, `Math` has no fields. It is used as a namespace.

This is common in Zig because Zig does not have a separate `class` or `namespace` keyword. Structs cover that role.

#### Struct Literals

A struct literal is the syntax used to create a struct value:

```zig
Point{
    .x = 10,
    .y = 20,
}
```

The general form is:

```zig
TypeName{
    .field_name = value,
    .field_name = value,
}
```

Example:

```zig
const Book = struct {
    title: []const u8,
    pages: u32,
};

const book = Book{
    .title = "The Zig Book",
    .pages = 300,
};
```

The type name comes first. The field assignments go inside braces.

#### Structs and Memory Layout

A normal Zig struct does not promise that fields are placed in memory exactly in the order you wrote them.

The compiler may choose a layout that is efficient.

For most beginner code, this does not matter. You should access fields by name, not by memory position.

When exact memory layout matters, Zig has special forms such as `extern struct` and `packed struct`.

For example, an `extern struct` is useful when matching a C struct layout:

```zig
const CPoint = extern struct {
    x: c_int,
    y: c_int,
};
```

A `packed struct` is useful when controlling bit-level layout:

```zig
const Flags = packed struct {
    read: bool,
    write: bool,
    execute: bool,
};
```

Do not use these forms by default. Use normal structs first. Reach for layout-specific structs only when you really need them.

#### A Practical Example

Here is a small example using a struct to represent a bank account:

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

const Account = struct {
    id: u64,
    balance: i64,
};

fn deposit(account: *Account, amount: i64) void {
    account.balance += amount;
}

pub fn main() void {
    var account = Account{
        .id = 1001,
        .balance = 500,
    };

    deposit(&account, 250);

    std.debug.print("account {} balance = {}\n", .{
        account.id,
        account.balance,
    });
}
```

Output:

```text
account 1001 balance = 750
```

This line is important:

```zig
fn deposit(account: *Account, amount: i64) void
```

The parameter `account: *Account` means the function receives a pointer to an `Account`.

That allows the function to modify the original account.

This call passes a pointer:

```zig
deposit(&account, 250);
```

The `&account` expression means “the address of `account`.”

Without a pointer, the function would receive a copy.

#### Copying Struct Values

Struct values are copied when assigned or passed by value.

Example:

```zig
const Point = struct {
    x: i32,
    y: i32,
};

var a = Point{
    .x = 1,
    .y = 2,
};

var b = a;
b.x = 99;
```

After this:

```text
a.x is still 1
b.x is 99
```

The assignment `var b = a;` copies the value.

This is simple and predictable. But if a struct is large, copying may be expensive. In that case, you may pass a pointer instead.

#### When to Use a Struct

Use a struct when several values belong together.

Good examples:

```zig
const Point = struct {
    x: f32,
    y: f32,
};

const User = struct {
    id: u64,
    name: []const u8,
};

const FileInfo = struct {
    path: []const u8,
    size: u64,
};
```

A struct gives a name to a concept in your program. Instead of passing separate loose values everywhere, you group them into one meaningful value.

Compare this:

```zig
fn draw(x: i32, y: i32, width: i32, height: i32) void {
    // ...
}
```

With this:

```zig
const Rect = struct {
    x: i32,
    y: i32,
    width: i32,
    height: i32,
};

fn draw(rect: Rect) void {
    // ...
}
```

The second version is easier to understand because the data has a name.

#### The Main Idea

A struct is Zig’s basic tool for building your own data types.

It lets you take separate values and combine them into one named concept.

```zig
const Person = struct {
    name: []const u8,
    age: u8,
};
```

This says: a `Person` has a `name` and an `age`.

That is the essence of structs. They make data organized, explicit, and easier to pass around.

