What is the difference between `let` and `var` in swift?

后端 未结 30 1485
隐瞒了意图╮
隐瞒了意图╮ 2020-11-22 11:09

What is the difference between let and var in Apple\'s Swift language?

In my understanding, it is a compiled language but it does not check

30条回答
  •  予麋鹿
    予麋鹿 (楼主)
    2020-11-22 11:59

    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 a variable 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]

    Value and Reference Type[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 Functions

    You can mark a struct's method as mutating

    1. Indicates that this function changes internal property values
    2. You are only able to call mutating function on var variable
    3. Result is visible when mutating function is finished
    func 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 function

    1. inout allows you to reassign/modify a passed(original) value.
    2. You are only able to pass var variable inside inout parameter
    3. Result is visible when function is finished

    inout has a next flow:

    1. passed value is copied into copied value before a function called
    2. copied value is assign into passed value after the function finished
    //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. Use var when you must.

    [Mutate structure]

提交回复
热议问题