Mutability in Swift Structs
In Swift, the mutability of a struct is tied directly to the concept of Value Types. Unlike classes (which are reference types), structs…
Mutability in Swift Structs

Beyond let vs. var: How Structs Actually Mutate in Swift
In Swift, the mutability of a struct is tied directly to the concept of Value Types. Unlike classes (which are reference types), structs copy their data when they are passed around.
Because of this, Swift enforces strict rules to ensure that state changes are predictable and safe.
1. The Power of let vs. var in Struct
The mutability of a struct instance depends entirely on the variable it is assigned to.
- Instance Mutability: Even if a struct has properties defined with
var, you cannot change them if the struct instance itself is assigned to aletconstant.
struct Person {
var name: String
}
let p1 = Person(name: "Joe")
p1.name = "Jane" // ❌ Error: Cannot assign to property: 'p1' is a 'let' constant
var p2 = Person(name: "Joe")
p2.name = "Jane" // This compiles now
- Property Mutability: If a property inside the struct is defined with
let, it can never be changed, even if the instance is assigned to avar.
struct Person {
let name: String
}
var p = Person(name: "Joe")
p.name = "Jane" // ❌ Error: Cannot assign to property: 'name' is a 'let' constant
2. Mutating Methods
By default, Swift assumes that methods on a struct do not modify the properties of that struct. If you want a method to change a property, you must explicitly mark it with the mutating keyword.
How it works under the hood?
When you call a mutating method, Swift doesn't just change a value in memory. Because it’s a value type, the mutating keyword actually allows the method to reassign “self” to a brand-new copy of the struct with the updated values.
struct Point {
var x = 0.0, y = 0.0
// This will fail to compile without 'mutating'
mutating func moveBy(x deltaX: Double, y deltaY: Double) {
x += deltaX
y += deltaY
}
}
3. Mutating Computed Properties
Computed properties (getters and setters) also follow mutability rules.
- The Setter: By default, a
setblock is always consideredmutatingbecause its job is to change the state. - The Getter: Normally, a
getblock is non-mutating (read-only). However, if reading a property needs to update a value, you must mark it asmutating get
struct FileParser {
var accessCount = 0
var preview: String {
mutating get {
accessCount += 1 // Mutating the state during a 'read'
return "Accessed \(accessCount) times"
}
}
}
The Catch: If you use a mutating get, you can no longer access that property on a let constant, because constants are not allowed to change—even just to "read" a value.
var parser1 = FileParser()
print(parser1.preview) // prints "Accessed 1 times"
let parser2 = FileParser()
print(parser2.preview) // ❌ Error: Cannot use mutating getter on immutable value: 'parser2' is a 'let' constant
4. Testing How a Struct Replaces Itself on mutating
When you modify a struct property, didSet fires for the entire parent object.
Note: In a class, this doesn't happen, because didSet only fires if you point the variable to an entirely different object instance, not when you change a property inside the current one.
// STRUCT BEHAVIOR
struct PointStruct {
var x = 0.0
}
var myPoint = PointStruct() {
didSet { print("The whole struct was swapped out!") }
}
myPoint.x = 20 // PRINTS: "The whole struct was swapped out!"
// CLASS BEHAVIOR
class PointClass {
var x = 0.0
}
var myClass = PointClass() {
didSet { print("This will never print.") }
}
myClass.x = 20 // SILENCE: The reference (address) stayed the same.
5. Arrays of Structs: The Collection Effect
Since an Array is also a struct in Swift, if it contains other structs, the rules of mutability apply to the entire chain. If you modify one property of a struct inside an array, the entire array is technically replaced.
struct Task {
var isDone: Bool
}
var todoList = [Task(isDone: false)] {
didSet { print("The entire list was updated!") }
}
// Changing one property of one element...
todoList[0].isDone = true
// PRINTS: "The entire list was updated!"
Take-Aways
- Variable Type Matters: Mutability is governed by
varvslet. - Explicit Permission:
mutatingis a required "permission slip" to change internal state. - Predictability: Value Semantics ensure that any change results in a conceptually “new” version, preventing hidden side effects.
Please feel free to leave a comment. Thank you!!!
메타데이터
- post_id
- 35f9f9ff37fd
- slug
- mutability-in-swift-structs-35f9f9ff37fd
- url
- https://medium.com/@tinys894/mutability-in-swift-structs-35f9f9ff37fd
- canonical_url
- https://medium.com/@tinys894/mutability-in-swift-structs-35f9f9ff37fd
- author_url
- https://medium.com/@tinys894
- status
- ok
- fetched_at
- 2026-07-10 18:30:51