let
- constant
var
- variable
[Constant vs variable]
[Struct vs Class]
Official doc docs.swift.org says
The value of a
constant
can’t be changed once it’s set, whereas avariable
can be set to a different value in the future.
This terminology actually describes a reassign mechanism
Mutability
Mutability - changeable - object's state can be changed after creation[About]
Reference Type(Class)
Swift's classes
are mutable
a-priory
var
+ class
It can be reassigned or changed
let
+ class
= constant of address
It can not be reassigned and can be changed
Value(Struct, Enum)
Swift's struct
can change their mutability status:
var
+ struct
= mutable
It can be reassigned or changed
let
+ struct
= *immutable
= constant of value
It can not be reassigned or changed
*immutable - check testStructMutability
test
Experiments:
class MyClass {
var varClass: NSMutableString
var varStruct: String
let letClass: NSMutableString
let letStruct: String
init(_ c: NSMutableString, _ s: String) {
varClass = c
varStruct = s
letClass = c
letStruct = s
}
}
struct MyStruct {
var varClass: NSMutableString
var varStruct: String
let letClass: NSMutableString
let letStruct: String
init(_ c: NSMutableString, _ s: String) {
varClass = c
varStruct = s
letClass = c
letStruct = s
}
//mutating function block
func function() {
// varClass = "SECONDARY propertyClass" //Cannot assign to property: 'self' is immutable
// varStruct = "SECONDARY propertyStruct" //Cannot assign to property: 'self' is immutable
}
mutating func mutatingFunction() {
varClass = "SECONDARY propertyClass"
varStruct = "SECONDARY propertyStruct"
}
}
Possible use cases
func functionVarLetClassStruct() {
var varMyClass = MyClass("propertyClass", "propertyStruct")
varMyClass.varClass = "SECONDARY propertyClass"
varMyClass.varStruct = "SECONDARY propertyStruct"
// varMyClass.letClass = "SECONDARY propertyClass" //Cannot assign to property: 'letClass' is a 'let' constant
// varMyClass.letStruct = "SECONDARY propertyStruct" //Cannot assign to property: 'letStruct' is a 'let' constant
let letMyClass = MyClass("propertyClass", "propertyStruct")
letMyClass.varClass = "SECONDARY propertyClass"
letMyClass.varStruct = "SECONDARY propertyStruct"
// letMyClass.letClass = "SECONDARY propertyClass" //Cannot assign to property: 'letClass' is a 'let' constant
// letMyClass.letStruct = "SECONDARY propertyStruct" //Cannot assign to property: 'letStruct' is a 'let' constant
var varMyStruct = MyStruct("propertyClass", "propertyStruct")
varMyStruct.varClass = "SECONDARY propertyClass"
varMyStruct.varStruct = "SECONDARY propertyStruct"
// varMyStruct.letClass = "SECONDARY propertyClass" //Cannot assign to property: 'letClass' is a 'let' constant
// varMyStruct.letStruct = "SECONDARY propertyStruct" //Cannot assign to property: 'letStruct' is a 'let' constant
let letMyStruct = MyStruct("propertyClass", "propertyStruct")
// letMyStruct.varClass = "SECONDARY propertyClass" //Cannot assign to property: 'letMyStruct' is a 'let' constant
// letMyStruct.varStruct = "SECONDARY propertyStruct" //Cannot assign to property: 'letMyStruct' is a 'let' constant
// letMyStruct.letClass = "SECONDARY propertyClass" //Cannot assign to property: 'letClass' is a 'let' constant
// letMyStruct.letStruct = "SECONDARY propertyStruct" //Cannot assign to property: 'letStruct' is a 'let' constant
}
mutating
- Mutating Struct's FunctionsYou can mark a struct's method as mutating
var
variablefunc testStructMutatingFunc() {
//given
var varMyStruct = MyStruct("propertyClass", "propertyStruct")
//when
varMyStruct.mutatingFunction()
//than
XCTAssert(varMyStruct.varClass == "SECONDARY propertyClass" && varMyStruct.varStruct == "SECONDARY propertyStruct")
// It is not possible to call a mutating function on a let variable
let letMyStruct = MyStruct("propertyClass", "propertyStruct")
// letMyStruct.mutatingFunction() //Cannot use mutating member on immutable value: 'letMyStruct' is a 'let' constant
}
inout
inside a functioninout
allows you to reassign/modify a passed(original) value.var
variable inside inout
parameterinout
has a next flow:
//InOut
func functionWithInOutParameter(a: inout MyClass, s: inout MyStruct) {
a = MyClass("SECONDARY propertyClass", "SECONDARY propertyStruct") //<-- assign
s = MyStruct("SECONDARY propertyClass", "SECONDARY propertyStruct") //<-- assign
}
func testInOutParameter() {
//given
var varMyClass = MyClass("PRIMARY propertyClass", "PRIMARY propertyStruct")
var varMyStruct = MyStruct("PRIMARY propertyClass", "PRIMARY propertyStruct")
//when
functionWithInOutParameter(a: &varMyClass, s: &varMyStruct)
//then
XCTAssert(varMyClass.varClass == "SECONDARY propertyClass" && varMyClass.varStruct == "SECONDARY propertyStruct")
XCTAssert(varMyStruct.varClass == "SECONDARY propertyClass" && varMyStruct.varStruct == "SECONDARY propertyStruct")
// It is not possible to pass let into inout parameter
let letMyClass = MyClass("PRIMARY propertyClass", "PRIMARY propertyStruct")
let letMyStruct = MyStruct("PRIMARY propertyClass", "PRIMARY propertyStruct")
// functionWithInOutParameter(a: &letMyClass, s: &letMyStruct) //Cannot pass immutable value as inout argument: 'letMyClass', 'letMyStruct' are 'let' constants
}
*You steal are able to mutate let + struct
func testStructMutability() {
//given
let str: NSMutableString = "propertyClass"
let letMyStruct = MyStruct(str, "propertyStruct")
//when
str.append(" SECONDARY")
//then
XCTAssert(letMyStruct.letClass == "propertyClass SECONDARY")
}
Use
let
whenever you can. Usevar
when you must.