Structs & Value Types

Reviewed & published by Brayan K

Structs are the backbone of Swift data modelling — Apple recommends them by default. By the end of this lesson you'll define structs, understand value semantics (copy-on-assign), use the free memberwise initializer, and write mutating methods.

Part of the free Swift course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.

What You'll Learn in This Lesson

1️⃣ Defining a Struct

Declare a struct and list its stored properties. Swift hands you a free memberwise initializer — one argument per property — so you rarely write init yourself.

// A STRUCT bundles related data (and behaviour) into a named type.
struct Point {
    var x: Int
    var y: Int
}

// Structs get a FREE memberwise initializer — no init() to write.
let origin = Point(x: 0, y: 0)
let p = Point(x: 3, y: 4)
print("p is (\(p.x), \(p.y))")     // p is (3, 4)

// Structs can hold different types and have defaults.
struct User {
    var name: String
    var age: Int = 0                 // default value
}
let u = User(name: "Ada")            // age defaults to 0
print("\(u.name), \(u.age)")        // Ada, 0

2️⃣ Value Semantics (Copy on Assign)

This is the defining trait of structs: assigning one to a new variable, or passing it to a function, makes an independent copy. Changing the copy never touches the original — no hidden sharing, no surprises.

// VALUE SEMANTICS: assigning a struct makes an independent COPY.
struct Point { var x: Int; var y: Int }

var a = Point(x: 1, y: 2)
var b = a                 // b is a COPY of a
b.x = 99                  // change only b

print("a.x = \(a.x)")     // a.x = 1   (unchanged!)
print("b.x = \(b.x)")     // b.x = 99

// Passing a struct to a function also copies it — the original is safe.
func moveRight(_ point: Point) -> Point {
    var copy = point
    copy.x += 10
    return copy
}
let moved = moveRight(a)
print("a.x = \(a.x), moved.x = \(moved.x)")   // a.x = 1, moved.x = 11

3️⃣ Mutating Methods

A method that changes the struct's own properties must be marked mutating. You can only call mutating methods on a var instance — a let struct is fully immutable.

// A method that changes the struct's own properties must be 'mutating'.
struct Counter {
    var count = 0

    mutating func increment() {       // changes self -> needs 'mutating'
        count += 1
    }

    func describe() -> String {       // only reads -> no 'mutating'
        return "count is \(count)"
    }
}

var c = Counter()
c.increment()
c.increment()
print(c.describe())                   // count is 2

// ⚠️ A 'let' struct is immutable — you can't call mutating methods on it.
// let fixed = Counter()
// fixed.increment()                  // ❌ compile error

Your turn. Fill in the blanks, then run it and check the output.

// 🎯 YOUR TURN — replace each ___ then run it in SwiftFiddle.

// 1) Define a struct 'Rectangle' with width and height (both Double).
___ Rectangle {                       // 👉 replace ___ with the keyword struct
    var width: Double
    var height: Double

    // 2) Add a method 'area' that returns width * height.
    func area() -> Double {
        return ___                     // 👉 replace ___ with width * height
    }
}

// 3) Make one using the free memberwise initializer.
let r = Rectangle(width: 3, height: 4)
print("Area: \(r.area())")

// ✅ Expected output:
//    Area: 12.0

Pro Tips

Common Errors (and the fix)

📋 Quick Reference

TaskCodeResult
Definestruct P { var x: Int }value type
Createlet p = P(x: 1)memberwise init
Copyvar b = aindependent copy
Mutatemutating func f()changes self
Immutablelet p = P(x: 1)cannot mutate
Inheritance—not supported

Mini-Challenge: Bank Account

Build it, run it, and check your output against the example in the comments — especially the part proving copies are independent.

// 🎯 MINI-CHALLENGE: Bank account
// 1. Define a struct 'Account' with a stored property 'balance' (Double, default 0).
// 2. Add a mutating method deposit(_ amount: Double) that adds to balance.
// 3. Add a mutating method withdraw(_ amount: Double) that subtracts.
// 4. Make a var account, deposit 100, withdraw 30, and print the balance.
// 5. Copy it: let snapshot = account. Deposit another 50 into account,
//    then print BOTH account.balance and snapshot.balance to prove copies
//    are independent (snapshot should NOT change).
//
// ✅ Example output:
//    Balance: 70.0
//    account: 120.0  snapshot: 70.0

// your code here

🎉 Lesson Complete!

Practice quiz

What keyword defines a struct?

  • structure
  • class
  • struct
  • type

Answer: struct. Structs are declared with the struct keyword.

Are structs value types or reference types?

  • Value types
  • Reference types
  • Neither
  • Both at once

Answer: Value types. Structs are value types — they are copied on assignment.

When you assign a struct to a new variable, what happens?

  • Both share the same instance
  • The original is deleted
  • It becomes a reference
  • An independent COPY is made

Answer: An independent COPY is made. Value types are copied, so the two variables are independent.

What does Swift automatically generate for a struct's initializer?

  • Nothing
  • A memberwise initializer
  • A deinitializer
  • A copy constructor you must override

Answer: A memberwise initializer. Structs get a free memberwise initializer covering their stored properties.

Why must a method that changes a struct's properties be marked `mutating`?

  • Because struct instances are otherwise treated as immutable within methods
  • For speed
  • To make it static
  • It's optional styling

Answer: Because struct instances are otherwise treated as immutable within methods. mutating signals the method changes the value-type instance's properties.

Can you call a mutating method on a struct stored in a `let` constant?

  • Yes
  • Only once
  • No — the instance is immutable
  • Only the first property

Answer: No — the instance is immutable. A let struct is immutable, so mutating methods are disallowed on it.

Given var a = Point(x:1,y:2); var b = a; b.x = 9 — what is a.x?

  • 9
  • 1
  • 0
  • nil

Answer: 1. b is a copy, so changing b.x leaves a.x unchanged at 1.

Do structs support inheritance from another struct?

  • Yes, fully
  • Only from classes
  • Only one level
  • No — structs cannot inherit from other structs

Answer: No — structs cannot inherit from other structs. Structs do not support inheritance; that's a class feature.

What is a good default choice in Swift for a simple data model?

  • Always a class
  • A struct (value type)
  • A tuple of 20 fields
  • A global variable

Answer: A struct (value type). Apple recommends preferring structs for most data models.

Can structs conform to protocols and have methods?

  • No
  • Only classes can
  • Yes — structs can have methods, computed properties, and conform to protocols
  • Only with inheritance

Answer: Yes — structs can have methods, computed properties, and conform to protocols. Structs support methods, computed properties, and protocol conformance.

Continue this course

Frequently asked questions

What does it mean that structs are value types?

It means a struct is copied whenever you assign it to a new variable, pass it to a function, or return it. The copy is independent: changing one does not affect the other. This makes structs predictable and safe — there's no hidden sharing, so you never accidentally mutate data that another part of your program relies on.

What is the memberwise initializer?

For every struct, Swift automatically generates an initializer that takes one argument per stored property, in declaration order: a struct with x and y gets Point(x:y:). You don't write it yourself. If you provide your own init, the memberwise one is replaced — though you can keep both by defining your custom init in an extension.

Why do some methods need the 'mutating' keyword?

Because struct instances are value types, their methods are not allowed to change the instance's stored properties unless explicitly marked mutating. The keyword documents that calling the method alters the value, and it also means you can only call it on a var instance — a let struct is fully immutable.

When should I choose a struct over a class?

Apple recommends preferring structs by default. Choose a struct for data models, values that are compared by their contents, and anything you want copied rather than shared — coordinates, money, settings, model objects. Reach for a class only when you specifically need reference semantics (shared mutable state), inheritance, or identity.

Can structs have methods and conform to protocols?

Yes. Structs can have stored and computed properties, instance and static methods, initializers, and they can conform to protocols like Equatable, Codable, and Comparable. What they cannot do is inherit from another struct — inheritance is exclusive to classes. For shared behaviour, structs use protocols and protocol extensions instead.

Related lessons