# Borrowing Without the Lecture.

Canonical: <https://journeytocode.io/borrowing-without-the-lecture/>

Our game has a `Player` and an `Enemy`

Then, the moment they fight, we strip them back down for parts:

```rust
enemy.health = attack(
    enemy.health,
    player.base_damage,
    player.bonus_damage,
);
```

We built two real game types.

The moment they interact, we go back to passing loose numbers around.

In this article, we are going to change `attack()` so it takes the player and the enemy themselves.

Along the way, Rust will refuse to compile our code three times.

Every time, it will be right.

By the end, our combat loop will say what the game actually does:

```rust
attack(&player, &mut enemy);
```

A player attacks an enemy.

Nothing gets torn apart.

---

## Our starting point

You need two structs and four small functions to follow along:

```rust
struct Player {
    base_damage: u32,
    bonus_damage: u32,
}

struct Enemy {
    name: String,
    health: u32,
}

fn click_damage(base: u32, bonus: u32) -> u32 {
    base.saturating_add(bonus)
}

fn health_after_hit(
    health: u32,
    damage: u32,
) -> u32 {
    health.saturating_sub(damage)
}

fn is_defeated(health: u32) -> bool {
    health == 0
}

fn attack(
    health: u32,
    base_damage: u32,
    bonus_damage: u32,
) -> u32 {
    let damage =
        click_damage(base_damage, bonus_damage);

    health_after_hit(health, damage)
}
```

At the bottom of `main.rs`, the `tests` module holds three tests for the small rules and one test that calls `attack()` directly:

```rust
#[test]
fn attack_reduces_enemy_health() {
    assert_eq!(attack(10, 5, 2), 3);
}
```

We will come back to that test once `attack()` changes.

Our combat loop looks like this:

```rust
fn main() {
    let player = Player {
        base_damage: 5,
        bonus_damage: 2,
    };

    let mut enemy = Enemy {
        name: String::from("Training Slime"),
        health: 20,
    };

    while !is_defeated(enemy.health) {
        enemy.health = attack(
            enemy.health,
            player.base_damage,
            player.bonus_damage,
        );

        println!(
            "{} health: {}",
            enemy.name,
            enemy.health
        );
    }

    println!("{} defeated!", enemy.name);
}
```

It works.

But `attack()` does not know what a player is.

It does not know what an enemy is.

It takes three numbers and hands back a fourth, and `main()` has to put that number back where it belongs.

What we want to write is closer to:

```rust
attack(player, enemy);
```

So let us try that.

---

## Hand the player to `attack()`

Let us start with the player and leave the enemy alone for a moment.

Change `attack()` so it takes a whole `Player` instead of two loose damage values:

```rust
fn attack(
    player: Player,
    health: u32,
) -> u32 {
    let damage = click_damage(
        player.base_damage,
        player.bonus_damage,
    );

    health_after_hit(health, damage)
}
```

The body barely changed.

We read the damage values from the player with the same dot syntax we used in `main()`.

Now update the call inside the loop:

```rust
enemy.health =
    attack(player, enemy.health);
```

That reads much better.

Run it:

```bash
cargo run
```

Rust refuses to build the program.

Trimmed down, the error says:

```text
error[E0382]: use of moved value: `player`

value moved here, in previous
iteration of loop
```

The full message is longer, and it suggests a few fixes, like cloning the player.

Some of them would work.

None of them is what we want, so let us figure out what actually happened.

The first attack would have been fine.

The second attack is the problem.

Where did the player go?

---

## The player moved

In Rust, every value has an owner.

Right now, `main()` owns `player`.

It created it, so it is responsible for it.

When we write:

```rust
attack(player, enemy.health)
```

and `attack()` asks for a `Player`, we are not lending the player to `attack()`.

We are giving it away.

Ownership moves into `attack()`.

When `attack()` finishes, the `Player` it owns is no longer available back in `main()`.

So on the next trip around the loop, `main()` tries to hand over a player it no longer owns.

Rust catches that before the program ever runs.

In game terms, our player attacked once and then vanished.

That is a bold balancing decision.

It is not ours.

The attack was supposed to defeat the enemy.

Not the player.

---

## Why did health never move?

We have been passing `enemy.health` into functions all along, and it never disappeared.

That is because `u32` implements Rust's `Copy` trait.

When we pass a `u32` by value, Rust can automatically make a copy, so the original remains available.

Our `Player` does not implement `Copy`, so passing it by value moves ownership instead.

You do not need to understand traits yet.

For now, the useful difference is:

```text
u32     → copied
Player  → moved
```

A `u32` gets photocopied.

A `Player` gets handed over.

We do not want to give the player away.

We want `attack()` to look at it.

Try it: this is the program with `attack()` taking a whole `Player`, and it fails to compile on purpose.

Run it and read the error for yourself.

You should see error code `E0382`, "use of moved value", pointing at the call inside the loop.

**Live example · read the move error**

```rust
struct Player {
    base_damage: u32,
    bonus_damage: u32,
}

struct Enemy {
    name: String,
    health: u32,
}

fn click_damage(base: u32, bonus: u32) -> u32 {
    base.saturating_add(bonus)
}

fn health_after_hit(health: u32, damage: u32) -> u32 {
    health.saturating_sub(damage)
}

fn is_defeated(health: u32) -> bool {
    health == 0
}

fn attack(player: Player, health: u32) -> u32 {
    let damage = click_damage(player.base_damage, player.bonus_damage);

    health_after_hit(health, damage)
}

fn main() {
    let player = Player {
        base_damage: 5,
        bonus_damage: 2,
    };

    let mut enemy = Enemy {
        name: String::from("Training Slime"),
        health: 20,
    };

    while !is_defeated(enemy.health) {
        enemy.health = attack(player, enemy.health);

        println!("{} health: {}", enemy.name, enemy.health);
    }

    println!("{} defeated!", enemy.name);
}
```

[Run and edit this example on the canonical article](https://journeytocode.io/borrowing-without-the-lecture/).

The next section fixes it with one character in two places.

If you want to fix it first, ask yourself what `attack()` needs to do with the player.

**Question:** After `attack(player, enemy.health)` runs once, why can `main()` still use `enemy.health` but not `player`?

1. Fields of a struct are never moved
2. `u32` implements `Copy`, so a copy was passed, but `Player` does not, so it moved
3. Rust only tracks moves for values that contain a `String`

**Answer:** 2. `u32` implements `Copy`, so a copy was passed, but `Player` does not, so it moved

> **Explanation:** Passing a `u32` by value copies it. `Player` is not `Copy`, so passing it by value hands ownership to `attack()`.

---

## Borrow the player with `&`

Rust lets a function borrow a value instead of owning it.

Add one character to the parameter type:

```rust
fn attack(
    player: &Player,
    health: u32,
) -> u32 {
    let damage = click_damage(
        player.base_damage,
        player.bonus_damage,
    );

    health_after_hit(health, damage)
}
```

`&Player` means:

> a reference to a `Player` that someone else owns

A reference lets `attack()` reach the player without taking ownership of it.

When the call finishes, the player is still sitting in `main()` where we left it.

Notice that the body did not change.

The dot works the same way through a reference, so:

```rust
player.base_damage
```

still reads the field.

The call needs the same `&`:

```rust
enemy.health =
    attack(&player, enemy.health);
```

`&player` says:

> let `attack()` borrow the player for this call

Run it:

```bash
cargo run
```

The Training Slime goes down in three hits again.

The player survives every one of them.

There is a bonus hiding in that `&`.

A plain `&` reference gives `attack()` read-only access to the player's fields.

If `attack()` tried to assign a new value to:

```rust
player.base_damage
```

Rust would refuse to compile it.

That is exactly the promise we want.

An attack needs to read the player.

It does not need to change the player.

**Question:** Inside `fn attack(player: &Player, ...)`, what does the line `player.base_damage = 9;` do?

1. Changes the caller's player, since a reference points at it
2. Fails to compile, because a plain `&` reference is read-only
3. Compiles, but only changes a private copy

**Answer:** 2. Fails to compile, because a plain `&` reference is read-only

> **Explanation:** Rust rejects it with `E0594`. The reference lets `attack()` read the player, not write to it.

---

## Now the enemy

The player is solved.

The enemy is still split apart:

```rust
enemy.health =
    attack(&player, enemy.health);
```

`attack()` gets a copy of the enemy's health, calculates a new number, and returns it.

Then `main()` writes that number back into the enemy.

What we really want is for `attack()` to change the enemy itself.

We just learned that borrowing keeps a value where it is.

Let us borrow the enemy too:

```rust
fn attack(
    player: &Player,
    enemy: &Enemy,
) {
    let damage = click_damage(
        player.base_damage,
        player.bonus_damage,
    );

    enemy.health =
        health_after_hit(enemy.health, damage);
}
```

Two things changed besides the enemy parameter.

There is no:

```rust
-> u32
```

anymore.

`attack()` is not handing back a number for someone else to store.

The result lives in the enemy.

Inside the function, we assign the new health directly to:

```rust
enemy.health
```

Update the call in `main()`:

```rust
attack(&player, &enemy);
```

Run it:

```bash
cargo run
```

Rust refuses again:

```text
error[E0594]: cannot assign to
`enemy.health`, which is behind
a `&` reference
```

You may also see a warning that `enemy` does not need to be mutable.

Ignore it for a moment.

We are about to need that `mut` again.

This is the promise from the last section working against us.

`&Enemy` lets us look at the enemy.

We did not come here to look.

A plain `&` reference is read-only.

That was perfect for the player.

It is wrong for the enemy because the entire point of an attack is that the enemy's health changes.

---

## Borrow the enemy with `&mut`

We have already met `mut`.

It is how we told Rust that our enemy is allowed to change.

References can express the same idea.

Change:

```rust
&Enemy
```

to:

```rust
&mut Enemy
```

Our attack becomes:

```rust
fn attack(
    player: &Player,
    enemy: &mut Enemy,
) {
    let damage = click_damage(
        player.base_damage,
        player.bonus_damage,
    );

    enemy.health =
        health_after_hit(enemy.health, damage);
}
```

`&mut Enemy` means:

> a mutable reference to an `Enemy` that someone else owns

In game terms:

> `attack()` may temporarily change this enemy, but it does not own the enemy.

The call needs to ask for the same thing:

```rust
attack(&player, &mut enemy);
```

This only works because `enemy` was already declared with:

```rust
let mut enemy
```

Rust will not let us borrow something mutably if the owner never agreed that it could change.

Run it:

```bash
cargo run
```

You should see:

```text
Training Slime health: 13
Training Slime health: 6
Training Slime health: 0
Training Slime defeated!
```

The same fight as before.

But now the signature tells the whole story:

```text
&Player     → attack reads the player
&mut Enemy  → attack changes the enemy
```

Nobody gets consumed.

Nobody gets torn apart.

Both are still in `main()`, ready for the next attack.

Try it: here is a small version of the fixed program that attacks twice.

Run it first.

You should see `Training Slime health: 13`, then `Training Slime health: 6`.

Then break it on purpose, one change at a time, and read each error:

- change `enemy: &mut Enemy` to `enemy: &Enemy` in `attack()` and you get `E0594`, the same error as before
- put `enemy: &mut Enemy` back, then remove `mut` from `let mut enemy` and you get `E0596`

**Live example · try breaking the borrow**

```rust
struct Player {
    base_damage: u32,
    bonus_damage: u32,
}

struct Enemy {
    name: String,
    health: u32,
}

fn click_damage(base: u32, bonus: u32) -> u32 {
    base.saturating_add(bonus)
}

fn health_after_hit(health: u32, damage: u32) -> u32 {
    health.saturating_sub(damage)
}

fn attack(player: &Player, enemy: &mut Enemy) {
    let damage = click_damage(player.base_damage, player.bonus_damage);

    enemy.health = health_after_hit(enemy.health, damage);
}

fn main() {
    let player = Player {
        base_damage: 5,
        bonus_damage: 2,
    };

    let mut enemy = Enemy {
        name: String::from("Training Slime"),
        health: 20,
    };

    attack(&player, &mut enemy);
    println!("{} health: {}", enemy.name, enemy.health);

    attack(&player, &mut enemy);
    println!("{} health: {}", enemy.name, enemy.health);
}
```

[Run and edit this example on the canonical article](https://journeytocode.io/borrowing-without-the-lecture/).

**Question:** Why does `attack(&player, &mut enemy)` need `let mut enemy`?

1. Because `&mut` makes Rust copy the enemy first
2. Because Rust will not lend out a mutable borrow of a value its owner never declared changeable
3. It does not; `&mut enemy` works on any variable

**Answer:** 2. Because Rust will not lend out a mutable borrow of a value its owner never declared changeable

> **Explanation:** Without `mut` on the variable, the borrow fails with `E0596`.

---

## One rule worth knowing now

There is one borrowing rule you will run into early, so here it is in game terms.

Suppose that, instead of the combat loop, `main()` grabs a reference to the enemy's name before attacking:

```rust
let name = &enemy.name;

attack(&player, &mut enemy);

println!("{name} took a hit!");
```

Rust refuses for the third time:

```text
error[E0502]: cannot borrow `enemy`
as mutable because it is also
borrowed as immutable
```

A borrow remains active until its last use.

`name` is used by the `println!()` after the attack, so that borrow is still active when `attack()` asks for permission to change the enemy.

Rust will not hand out a mutable borrow while that reading borrow is still being used.

Our combat loop never hits this problem because each borrow is finished before the next conflicting access begins:

```rust
attack(&player, &mut enemy);

println!(
    "{} health: {}",
    enemy.name,
    enemy.health
);
```

In this case, the mutable borrow is finished when `attack()` returns.

Then `println!()` is free to read the enemy.

That is the beginner version of the rule:

> **For the same data at the same time: many readers, or one writer, but not both.**

You do not need more than that today.

**Question:** Why does Rust reject reading `name = &enemy.name` before `attack(&player, &mut enemy)` when `name` is printed afterward?

1. A `&` borrow can never be followed by a `&mut` borrow of the same value
2. The `&` borrow is still in use when `attack()` asks for `&mut`, so a reader and a writer overlap
3. `attack()` takes ownership of `enemy`

**Answer:** 2. The `&` borrow is still in use when `attack()` asks for `&mut`, so a reader and a writer overlap

> **Explanation:** A borrow lasts until its last use. If nothing used `name` after the attack, the program would compile.

**Coding challenge: End the borrow in time**

This starter fails to compile on purpose, because the lesson here is the error.

Fix it without changing `attack()`. Keep the names `attack` and `main` and the shape of `Player` and `Enemy`, because the checks call them. Press **Check my code** and it will tell you how you are doing.

**Expected result:** it compiles and prints `Training Slime took a hit! Health: 13`.

**Fix the borrow conflict**

```rust
struct Player {
    base_damage: u32,
    bonus_damage: u32,
}

struct Enemy {
    name: String,
    health: u32,
}

fn click_damage(base: u32, bonus: u32) -> u32 {
    base.saturating_add(bonus)
}

fn health_after_hit(health: u32, damage: u32) -> u32 {
    health.saturating_sub(damage)
}

fn attack(player: &Player, enemy: &mut Enemy) {
    let damage = click_damage(player.base_damage, player.bonus_damage);

    enemy.health = health_after_hit(enemy.health, damage);
}

fn main() {
    let player = Player {
        base_damage: 5,
        bonus_damage: 2,
    };

    let mut enemy = Enemy {
        name: String::from("Training Slime"),
        health: 20,
    };

    // TODO: this borrow is still in use after the attack. Make the program compile.
    let name = &enemy.name;

    attack(&player, &mut enemy);

    println!("{name} took a hit! Health: {}", enemy.health);
}

```

<details>
<summary>Spoiler: the checks for this challenge</summary>
<p>These tests run when you press Check my code on the original article. Reading them first gives away the answer.</p>
<pre><code class="language-rust">/// It compiles now, and the program still runs from start to finish.
#[test]
fn main_still_runs() {
    main();
}

/// It compiles, but attack() no longer does its job. We only wanted to move the borrow, not the damage.
#[test]
fn attack_still_lands() {
    let player = Player {
        base_damage: 5,
        bonus_damage: 2,
    };
    let mut enemy = Enemy {
        name: String::from("Training Slime"),
        health: 20,
    };

    attack(&player, &mut enemy);

    assert_eq!(enemy.health, 13);
}
</code></pre>
</details>

[Run and edit this example on the canonical article](https://journeytocode.io/borrowing-without-the-lecture/).

> **Tip:** The error is `E0502`. A borrow ends at its last use, so ask where `name` needs to start borrowing.

---

## Update the test

Our `attack()` test still passes three loose numbers, so it needs the new signature:

```rust
#[test]
fn attack_reduces_enemy_health() {
    let player = Player {
        base_damage: 5,
        bonus_damage: 2,
    };

    let mut enemy = Enemy {
        name: String::from("Training Slime"),
        health: 10,
    };

    attack(&player, &mut enemy);

    assert_eq!(enemy.health, 3);
}
```

The rule it checks has not changed.

An attack with five base damage and two bonus damage takes ten health down to three.

What changed is how the test says it.

It builds a player.

It builds an enemy.

It lets one attack the other.

Then it checks the enemy afterward.

That reads like the game.

The other three tests do not touch `attack()`, so they stay exactly as they were.

Run them:

```bash
cargo test
```

All four should pass.

We do not need a separate test proving that `attack()` does not change the player.

With our current `Player` type, an `&Player` reference does not allow `attack()` to assign new values to the player's fields.

The compiler checks that for us every time we build.

---

## The complete program

If you have been following along in your editor, here is everything in one place.

At this point, `src/main.rs` should look like this:

```rust
struct Player {
    base_damage: u32,
    bonus_damage: u32,
}

struct Enemy {
    name: String,
    health: u32,
}

fn click_damage(base: u32, bonus: u32) -> u32 {
    base.saturating_add(bonus)
}

fn health_after_hit(
    health: u32,
    damage: u32,
) -> u32 {
    health.saturating_sub(damage)
}

fn is_defeated(health: u32) -> bool {
    health == 0
}

fn attack(
    player: &Player,
    enemy: &mut Enemy,
) {
    let damage = click_damage(
        player.base_damage,
        player.bonus_damage,
    );

    enemy.health =
        health_after_hit(enemy.health, damage);
}

fn main() {
    let player = Player {
        base_damage: 5,
        bonus_damage: 2,
    };

    let mut enemy = Enemy {
        name: String::from("Training Slime"),
        health: 20,
    };

    while !is_defeated(enemy.health) {
        attack(&player, &mut enemy);

        println!(
            "{} health: {}",
            enemy.name,
            enemy.health
        );
    }

    println!("{} defeated!", enemy.name);
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn click_damage_adds_base_and_bonus() {
        assert_eq!(click_damage(3, 4), 7);
    }

    #[test]
    fn health_never_drops_below_zero() {
        assert_eq!(
            health_after_hit(3, 10),
            0
        );
    }

    #[test]
    fn zero_health_is_defeated() {
        assert!(is_defeated(0));
        assert!(!is_defeated(1));
    }

    #[test]
    fn attack_reduces_enemy_health() {
        let player = Player {
            base_damage: 5,
            bonus_damage: 2,
        };

        let mut enemy = Enemy {
            name: String::from("Training Slime"),
            health: 10,
        };

        attack(&player, &mut enemy);

        assert_eq!(enemy.health, 3);
    }
}
```

Run both:

```bash
cargo run
cargo test
```

The Training Slime should fall in three hits, and all four tests should pass.

---

## What we learned

Along the way, we encountered:

- ownership
- moves
- `Copy` values
- `&T` references
- `&mut T` references
- functions that change a value instead of returning a new one
- when borrows stop being used
- why Rust prevents conflicting access

You do not need to memorize all of that yet.

The important change is what our attack says.

We started with:

```rust
enemy.health = attack(
    enemy.health,
    player.base_damage,
    player.bonus_damage,
);
```

We ended with:

```rust
attack(&player, &mut enemy);
```

The player is read.

The enemy is changed.

Both stay where they belong.

And the compiler now checks that `attack()` keeps its side of that deal.

---

## There is a bigger shape missing

Look at what `main()` is holding now:

```text
player
enemy
the combat loop
```

That is a fight.

It is not a game.

When the Training Slime dies, the program simply ends.

There is no next enemy.

There is no stage counter.

Nobody earns anything for winning.

And every one of those things would become another loose variable inside `main()`:

```text
player
enemy
stage
gold
experience
```

We have seen this problem before.

Three numbers were not a player.

A pile of variables in `main()` is not a game.

The pieces that make up our game need one place to live, and one place that decides what happens when a player clicks.

Next, we will put the game in one place.

**Small function. Bigger game.** [Join the discussion on the canonical article](https://journeytocode.io/borrowing-without-the-lecture/)
