Structures and value semantics

Swift · Essentials · 12 min

Structs are Swift's default building block; SwiftUI views and most model types are structs.

A struct groups related data and behavior: struct Point { var x: Double; var y: Double }. Swift generates a memberwise initializer, Point(x: 1, y: 2), as long as you don't write your own init in the main declaration.

Structs are value types. Assignment and passing copy the value, so each variable owns its data independently. This makes reasoning local: no other code can change your copy. Most of the standard library (Int, String, Array, Dictionary) is built from structs.

Methods are functions inside the type. A method that changes stored properties must be marked `mutating`, and can only be called on a var. Inside a method, self refers to the instance; you rarely need to write it.

If you declare an instance with let, all its properties become immutable, even those declared var.

Use static for type-level properties and methods: static let origin = Point(x: 0, y: 0).

Apple's guidance: start with a struct, and reach for a class only when you need identity (one shared instance that several parts of the program observe), inheritance, or Objective-C interop. Structs can still conform to protocols and gain behavior through extensions.

Conforming to Equatable or Hashable is usually automatic: just declare the conformance and the compiler synthesizes == and hash(into:).

Example

struct Point: Equatable {
    var x: Double
    var y: Double
    static let origin = Point(x: 0, y: 0)

    func distance(to other: Point) -> Double {
        ((x - other.x) * (x - other.x) + (y - other.y) * (y - other.y)).squareRoot()
    }
    mutating func move(dx: Double, dy: Double) {
        x += dx; y += dy
    }
}

var a = Point(x: 3, y: 4)
var b = a
b.move(dx: 1, dy: 0)
print(a.x, b.x)                       // 3.0 4.0
print(a.distance(to: .origin))        // 5.0
print(a == Point(x: 3, y: 4))         // true

let fixed = Point(x: 1, y: 1)
// fixed.move(dx: 1, dy: 1)           // error: fixed is a let constant

Remember

  • Structs are copied on assignment — each variable owns its value
  • Methods that modify properties need mutating
  • Default to struct; use a class when you need identity or inheritance

Watch out for

  • Adding a custom init inside the struct body and losing the memberwise initializer — put it in an extension to keep both.

Check yourself

  1. `let p = Point(x: 1, y: 1)` — can you call the mutating method `p.move(dx: 1, dy: 0)`?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: docs.swift.org/swift-book/documentation/the-swift-programming-language/classesandstructures/