Structs
Swift structs are value types — copied on assignment, no reference identity. Use them for data: models, view state, value objects. The compiler synthesises memberwise initialisers, Equatable, and Codable.
Memberwise init, mutating, protocols
EXAMPLE
// 1) Basic struct
struct Point {
var x: Double
var y: Double
}
let p = Point(x: 1, y: 2) // memberwise init auto-generated
// 2) Value semantics — copy, not reference
var a = Point(x: 1, y: 2)
var b = a // copy
b.x = 99
print(a.x) // 1 — unchanged
// 3) Mutating method — required when modifying self
struct Counter {
var value = 0
mutating func inc() { value += 1 }
}
var c = Counter()
c.inc() // c.value == 1
// let cc = Counter(); cc.inc() // ERROR — can't mutate a let
// 4) Computed properties
struct Rect {
var width: Double
var height: Double
var area: Double { width * height }
var aspect: Double {
get { width / height }
set { width = height * newValue }
}
}
// 5) Auto-conformances when possible — Equatable, Hashable, Codable
struct User: Equatable, Hashable, Codable {
let id: UUID
var name: String
var email: String
}
// Free synthesis: ==, hash(into:), Codable encode/decode
let u1 = User(id: UUID(), name: "Ada", email: "a@x.com")
let u2 = u1
print(u1 == u2) // true
let json = try JSONEncoder().encode(u1)
let back = try JSONDecoder().decode(User.self, from: json)
// 6) Custom initialiser
struct Money {
let amount: Decimal
let currency: String
init(_ amount: Decimal, in currency: String = "AUD") {
self.amount = amount
self.currency = currency
}
}
let price = Money(9.99)
// 7) Generic struct
struct Stack<Element> {
private var items: [Element] = []
mutating func push(_ e: Element) { items.append(e) }
mutating func pop() -> Element? { items.popLast() }
var top: Element? { items.last }
var count: Int { items.count }
}
var nums = Stack<Int>()
nums.push(1); nums.push(2)
// 8) Extensions — add methods to a struct from outside
extension Point {
func distance(to other: Point) -> Double {
hypot(x - other.x, y - other.y)
}
}
let d = p.distance(to: Point(x: 4, y: 6))
// 9) Conform to a protocol
protocol Describable { var description: String { get } }
struct Product: Describable {
let name: String
let price: Double
var description: String { "\(name) — $\(price)" }
}
// 10) Property wrappers — declarative property behaviour
@propertyWrapper
struct Capitalised {
private var value: String = ""
var wrappedValue: String {
get { value }
set { value = newValue.capitalized }
}
}
struct Person {
@Capitalised var name: String
}
var alice = Person(name: "ada")
print(alice.name) // "Ada"
// 11) Struct vs class — when to choose which
// Struct (value): data, model layer, immutable-by-default, no shared identity needed
// Class (reference): need shared identity, reference cycles via @State / observation, ObjC interop
// Default to struct; reach for class when you NEED reference semantics.
// 12) Copy-on-write — efficient large value types
// Stdlib types (Array, Dictionary, String, Set) are structs with copy-on-write
// Assigning is O(1); copy only happens when mutated AND the storage has another owner.
Why it matters
Default to struct in Swift. Value semantics + auto-conformance + copy-on-write give you safety and performance for free; switch to class only when reference identity is genuinely needed.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Example
Example
struct User {
var name: String
var age: Int
mutating func happyBirthday() { age += 1 }
}
var u = User(name: "Ada", age: 36)
u.happyBirthday()
Try it Yourself »
Exercise
Method that mutates self on a struct.
func bump() { age += 1 }
Eight letters.
Discussion
Loading…