---
title: "10.1 Introduction to program-defined types"
description: "Why every language lets you define your own types, how a struct groups related data under one name, and Rust's naming conventions for types."
url: "https://learnrust.net/chapter-10/introduction-to-program-defined-types/"
last_updated: "2026-06-13"
---

# 10.1 Introduction to program-defined types

Everything you've built for nine chapters has used types the language handed you: `i32`, `f64`, `bool`, `char`, the unit `()`, tuples, `String`, `&str`. They've been enough because the problems were small. Read a number, double it, print it. Roll a die. Find the first word. Each of those programs juggled a handful of loose values, and loose values were fine.

Real programs aren't like that. A program that tracks a customer needs a name, an email, an account balance, and a signup date, and those four facts are not four separate things. They're one thing: a customer. The moment you write a function that takes all four as parameters, you feel the strain.

```rust
fn send_receipt(name: &str, email: &str, balance: f64, signup_year: u32) {
    // ...
}
```

Four parameters that must always travel together, in the right order, or the program is wrong in a way the types can't catch. Swap `balance` and `signup_year` at one call site and you've mailed a receipt for the year 2026 dollars to an account created in $48.50. Both are numbers; the compiler shrugs. This is the problem custom types solve.

## A type you define yourself

Rust lets you bundle related values into a single named type called a **struct** (short for *structure*). Here is the customer, as one type instead of four parameters:

```rust
struct Customer {
    name: String,
    email: String,
    balance: f64,
    signup_year: u32,
}
```

`Customer` is now a type, exactly as real as `i32`. You can store one in a variable, pass one to a function, return one from a function, and put the four fields where they belong: inside the thing they describe. The function signature collapses to a single, honest parameter:

```rust
fn send_receipt(customer: &Customer) {
    // ...
}
```

We'll spend this whole chapter learning to define, build, and use structs, and then to attach behavior to them with methods. The next lesson shows the syntax for creating one and reading its fields; this lesson is about *why* the feature exists and what to call your types.

## Program-defined types

A struct is one example of a broader idea. The types built into the language (`i32`, `bool`, and friends) are **fundamental types**, the vocabulary lesson [4.1](https://learnrust.net/chapter-4/introduction-to-fundamental-data-types/) introduced. A type you declare in your own code is a **program-defined type**: it doesn't exist until you write it down, and it exists only for programs that include that definition.

Rust has a few kinds. Structs (this chapter) group several values that are all present at once: a customer *has* a name *and* an email *and* a balance. Enums (chapter 11) describe a value that is *one of* several alternatives: a traffic light is red *or* yellow *or* green, never two at once. Those two kinds, "and" types and "or" types, are the entire foundation, and almost every type you'll ever use, including `String` itself, is built from them.

> **Key insight**
>
> A struct answers "what pieces make up this thing?" An enum answers "which of these things is it?" Reach for a struct when the parts coexist (a point has *both* an x and a y); reach for an enum when the value is exactly one of a fixed set of options (chapter 11). Most data modeling in Rust is choosing between these two questions.

## Naming your types

The compiler doesn't care what you name a type, but the community has settled the question and the tooling enforces it, the same way lesson [1.8](https://learnrust.net/chapter-1/keywords-and-identifiers/) laid out names for variables and functions. Variables and functions are `snake_case`; types are `UpperCamelCase` (also called PascalCase): each word capitalized, no underscores. `Customer`, `BankAccount`, `HttpResponse`, `Point`.

This isn't only fashion. Because casing is consistent, a Rust reader can tell a *type* from a *value* at a glance, without context: `Customer` is a type, `customer` is probably a variable holding one. Field names, being values, follow the variable rule and stay `snake_case`: `signup_year`, not `signupYear` or `SignupYear`.

Name a type after the noun it represents, singular: `Customer`, not `Customers` or `CustomerData`. A value of the type is one customer; a collection of them gets pluralized at the variable, like `let customers = ...`. Pick the most specific accurate noun. `Point` beats `Thing`; `EmailAddress` beats `String` when the extra precision earns its keep (a technique chapter 10.4 returns to).

```rust
struct WeatherReading {   // UpperCamelCase type name
    city: String,         // snake_case field names
    temperature_c: f64,
    is_raining: bool,
}
```

> **Best practice**
>
> Name types with a singular `UpperCamelCase` noun and fields with `snake_case`. If you slip, the `non_camel_case_types` and `non_snake_case` lints will warn you, just like the constant-naming warning you met in lesson [5.1](https://learnrust.net/chapter-5/constants-and-statics/). Let the compiler keep you honest.

## Why this is the chapter where the course changes gears

The first nine chapters were a strict apprenticeship: the rules of values, ownership, and borrowing, taught on the small set of types the language ships. You earned a lot of compiler errors. The payoff starts here. With structs and (chapter 11) enums, you stop arranging the language's furniture and start building rooms of your own, and every concept you've already paid for, moves, borrows, the four-row parameter table from lesson [9.4](https://learnrust.net/chapter-9/references-and-functions/), applies unchanged to the types you invent. A `&Customer` borrows for the same reason a `&String` does. That's the whole reason the borrowing chapters came first.

## Quiz time

**Question #1**

Why is bundling `name`, `email`, and `balance` into a `Customer` struct safer than passing them as three separate parameters?

<details class="solution">
<summary>Show solution</summary>

Because the three values describe one thing and must always travel together. As separate parameters they can be supplied in the wrong order or partially, and if two share a type (two `String`s, say) the compiler can't catch a swap. A single `Customer` keeps them grouped under one name, so there's one value to pass and no order to get wrong at the call site.

</details>

**Question #2**

Judge each name as a struct type name: conventional, unconventional, or invalid.

a) `bank_account`  b) `BankAccount`  c) `Bankaccount`  d) `Bank_Account`  e) `2Player`

<details class="solution">
<summary>Show solution</summary>

a) Unconventional: that's the variable/function style; the `non_camel_case_types` lint warns. b) Conventional `UpperCamelCase`. c) Unconventional: it compiles, but "account" should be capitalized (`BankAccount`). d) Unconventional: underscores don't belong in type names. e) Invalid: identifiers can't start with a digit, the rule from lesson [1.8](https://learnrust.net/chapter-1/keywords-and-identifiers/).

</details>

**Question #3**

You're modeling a value that is always exactly one of: `Pending`, `Shipped`, or `Delivered`. Should that be a struct or an enum, and why?

<details class="solution">
<summary>Show solution</summary>

An enum. The value is *one of* a fixed set of alternatives, never two at once, which is the "or" question enums answer. A struct is for things whose parts coexist. Chapter 11 builds exactly this kind of type.

</details>

Enough motivation. Next lesson writes a struct, builds one, and reads its fields, with the move and borrow rules from chapters 8 and 9 quietly riding along.

## Sitemap

See the full [sitemap](https://learnrust.net/sitemap.md) for all pages.
