I don't know if I am just too tired, but I think there is more to it. (I tried two cups of coffee, but still couldn't solve the problem...)
I want to make a variable read-only from the outside, but writable through methods. (So like in that example I can make sure favoriteNumber is only single-digit.
(I don't want to make it a computed property and do that in get {}, set{}, because in my other project I want to modify the variable based on a value different than "newValue" of set {})
struct Person {
var name: String
private(set) var favoriteNumber: Int? // Should only be single-digit
init(name: String, number: Int) {
self.name = name
// Make sure favorite number is single-digit
guard number >= 0 && number < 10 else {
self.favoriteNumber = nil
}
self.favoriteNumber = number
}
func changeFavoriteNumber(number: Int) {
guard number >= 0 && number < 10 else { return }
self.favoriteNumber = number
}
}
.
The line
self.favoriteNumber = number
in the function
changeFavoriteNumber(number:)
raises the error
"Cannot assign to property: 'self' is immutable"
and suggests "Mark method 'mutating' to make 'self' mutable". But that's not what I want, since I don't want to modify an instance of type Person, but a mutable variable... (var favoriteNumber)
Supposed to be used in that way:
let frank = Person.init(name: "Frank", number: 9)
frank.changeFavoriteNumber(number: 8)
I have no idea what's going on here (even after 3 coffees now :)
Structs are not copied on mutation. They may be mutated in-place. But every variable is a new copy (including passing the struct value as a function parameter). In functional languages values are truly immutable (so in order to change oven's temperature you need create a new oven in a new kitchen in a new house).
A struct type is not immutable. Yes, strings are. Making your own type immutable is easy, simply don't provide a default constructor, make all fields private and define no methods or properties that change a field value. Have a method that should mutate the object return a new object instead.
SwiftUI views are structs. Structs are immutable by default (so the values inside are immutable too) Methods (functions) marked with mutating can mutate the values of properties. But that's not allowed in SwiftUI, because it uses a computed property.
In Swift, structs are value types whereas classes are reference types. When you copy a struct, you end up with two unique copies of the data. When you copy a class, you end up with two references to one instance of the data. It's a crucial difference, and it affects your choice between classes or structs.
Structs are value types, and have different semantics than classes. A variable storing an instance of a class is stored as a reference to the actual object elsewhere in memory; this means that you can have two variables pointing to the same object, and you can modify a class's members whether or not the variables referencing it are mutable.
A struct is different. A variable storing an instance of a struct
stores the struct's members directly, instead of as a reference to an object somewhere else. This means that passing a struct to a function or another variable creates a copy of it, and modifying a struct
directly modifies the variable storing it.
Therefore, a struct is immutable unless it's stored in a var
. Functions that mutate the struct must be declared mutating
as the compiler suggests, so that the compiler can enforce that only non-mutating functions are called on let
structs.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With