swift中`let`和`var`有什么区别?

Edw*_*ard 302 swift

是什么区别let,并var在苹果的雨燕语言?

根据我的理解,它是一种编译语言,但它不会在编译时检查类型.这让我感到困惑.编译器如何知道类型错误?如果编译器没有检查类型,那么生产环境是不是有问题?

jm6*_*666 397

let关键字定义一个常数:

let theAnswer = 42
Run Code Online (Sandbox Code Playgroud)

theAnswer无法改变之后.这就是为什么weak不能用任何东西写的原因let.他们需要在运行时更改,您必须使用它var.

var定义了一个普通变量.

有趣的是:

在编译时不需要知道常量的值,但必须将该值分配一次.

另一个奇怪的功能

您可以使用几乎任何您喜欢的字符来表示常量和变量名称,包括Unicode字符:

let  = "dogcow"
Run Code Online (Sandbox Code Playgroud)

节选自:Apple Inc."The Swift Programming Language."iBooks.https://itunes.apple.com/WebObjects/MZStore.woa/wa/viewBook?id=881256329

编辑

因为评论要求在答案中添加其他事实,将其转换为社区维基答案.随意编辑答案,使其更好.

  • @ bames53好吧,我只是不确定,我想要调试一个程序,如:`if === {=♠︎}`:);) (127认同)
  • 这个答案虽然是最受欢迎的,却没有提及在引用对象而不是值类型时让/ var的行为.关键是在这两种情况下,您仍然可以更改对象的属性,但不能修改指针以引用另一个对象.从涉及整数和字符串的基本示例来看,这并不是很明显. (29认同)

Krz*_*zak 32

根据The Swift Programming Language Book

与C一样,Swift使用变量来存储和通过标识名称引用值.Swift还广泛使用其值无法更改的变量.这些被称为常量,并且比C中的常量强大得多.

两个varlet引用,因此let是一个常量引用.使用基本类型并没有真正显示出let与众不同的方式const.将它与类实例(引用类型)一起使用时会出现差异:

class CTest
{
    var str : String = ""
}

let letTest = CTest()
letTest.str = "test" // OK

letTest.str = "another test" // Still OK

//letTest = CTest() // Error

var varTest1 = CTest()
var varTest2 = CTest()
var varTest3 = CTest()

varTest1.str = "var 1"
varTest2.str = "var 2"
varTest3 = varTest1
varTest1.str = "var 3"

varTest3.str // "var 3"
Run Code Online (Sandbox Code Playgroud)

  • 我同意您的术语是错误的。var和let与所绑定的标识符是否为引用无关。如果类型是`struct`类型,则从概念上讲是一个值。如果类型是“类”,则在概念上是引用,如果使用“ let”,则引用是常量。如果`CTest`是一个结构体,那么所有`letTest`的分配都不会起作用。 (2认同)

atx*_*txe 14

let用于定义常量和var定义变量.


yoA*_*ex5 9

let- constant
var-variable

[常量 vs 变量]
[结构 vs 类]

官方文档docs.swift.org

a 的值constant一旦设置就不能更改,而 avariable可以在将来设置为不同的值。

这个术语实际上描述了一种重新分配机制

可变性

Mutability - 可变 - 对象的状态可以在创建后改变[关于]

值和引用类型[关于]

引用类型(类)

斯威夫特的classesmutableA-修道院

var+class
可以重新分配更改

let+ class=地址的常数
它可以重新分配,并且可以改变

值(结构,枚举)

Swiftstruct可以改变它们的可变性状态:

var+ struct=mutable
可以重新分配更改

let+ struct= * immutable=的值恒定
它可以重新分配改变

*不可变 - 检查testStructMutability测试

实验:

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"
    }
}
Run Code Online (Sandbox Code Playgroud)

可能的用例

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
    
}
Run Code Online (Sandbox Code Playgroud)

mutating - 改变结构的功能

您可以将结构的方法标记为mutating

  1. 表示这个函数改变了内部属性值
  2. 您只能在var变量上调用变异函数
  3. 变异函数完成后结果可见
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
}
Run Code Online (Sandbox Code Playgroud)

inout 在函数内部

  1. inout 允许您重新分配/修改传递的(原始)值。
  2. 您只能varinout参数内部传递变量
  3. 功能完成后结果可见

inout 有下一个流程:

  1. 传递的值在调用函数之前被复制到复制值中
  2. 函数完成后,复制的值被分配到传递的值中
//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
}     
Run Code Online (Sandbox Code Playgroud)

*你偷是能够变异 let + struct

func testStructMutability()  {
    //given
    let str: NSMutableString = "propertyClass"
    let letMyStruct = MyStruct(str, "propertyStruct")
    
    //when
    str.append(" SECONDARY")
    
    //then
    XCTAssert(letMyStruct.letClass == "propertyClass SECONDARY")
}
Run Code Online (Sandbox Code Playgroud)

let尽可能使用。var必要时使用。

[变异结构]


Luc*_*ier 7

通过可变性/不可变性概念来表达这种差异可能更好,这是正确的范式和对象空间中的实例可变性,它大于唯一的"常数/变量"通常概念.此外,这更接近于Objective C方法.

2种数据类型:值类型和引用类型.

在价值类型的背景下:

'let'定义一个常量值(不可编码).'var'定义了一个可变的值(可变).

let aInt = 1   //< aInt is not changeable

var aInt = 1   //< aInt can be changed
Run Code Online (Sandbox Code Playgroud)

在参考类型的上下文中:

数据的标签不是值,而是对值的引用.

如果aPerson = Person(名字:Foo,第一名:Bar)

aPerson不包含此人的数据,但包含对此人数据的引用.

let aPerson = Person(name:Foo, first:Bar)
               //< data of aPerson are changeable, not the reference

var aPerson = Person(name:Foo, first:Bar)
               //< both reference and data are changeable.

eg:
var aPersonA = Person(name:A, first: a)
var aPersonB = Person(name:B, first: b)

aPersonA = aPersonB

aPersonA now refers to Person(name:B, first: b)
Run Code Online (Sandbox Code Playgroud)

  • Unmutability?这是不可能的!当然是反制的.我认为你在寻找可能是"不变性"的词:-) (4认同)
  • 但是如果`aPerson` 有setter 你可以修改它的属性吗?所以 `let` 不会使 `Person` 不可变。 (2认同)

小智 6

"Swift编程语言"文档的" 声明常量和变量"部分指定了以下内容:

使用let关键字声明常量,使用var关键字声明变量.

确保了解这对参考类型的工作原理.与值类型不同,尽管引用类型的实例被声明为常量,但对象的基础属性可以更改.请参阅文档的" 类是引用类型"部分,并查看更改frameRate属性的示例.


Raj*_*han 6

非常简单:

  • let 是不变的.
  • var 是动态的.

一点描述:

let创造一个常数.(有点像NSString).设置后,您无法更改其值.您仍然可以将其添加到其他内容并创建新变量.

var创建一个变量.(有点像NSMutableString)所以你可以改变它的价值.但这已得到多次回答.


ric*_*ter 5

let定义一个“常数”。它的值设置一次且仅一次,但不一定在您声明时设置。例如,您let用来定义必须在初始化期间设置的类中的属性:

class Person {

    let firstName: String
    let lastName: String

    init(first: String, last: String) {
         firstName = first
         lastName = last
         super.init()
    }
}
Run Code Online (Sandbox Code Playgroud)

使用此设置,分配给firstNamelastName在调用(例如)之后Person(first:"Malcolm", last:"Reynolds")创建Person实例是无效的。

必须在编译时为所有变量(letvar)定义一个类型,并且任何尝试设置变量的代码只能使用该类型(或子类型)。您可以在运行时分配,但必须在编译时知道其类型