"let"关键字在Swift中的工作原理是什么?

Max*_*kov 25 constants swift

我在指南中读到了这个简单的解释:

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

但我想要比这更详细一些.如果常量引用了一个对象,我还可以修改它的属性吗?如果它引用了一个集合,我可以添加或删除它中的元素吗?我来自C#背景; 是否类似于readonly工作(除了能够在方法体中使用它),如果不是,它有什么不同?

ric*_*ter 44

let有点像constC中的指针.如果使用a引用对象let,则可以更改对象的属性或对其调用方法,但不能为该标识符分配不同的对象.

let也对集合和非对象类型有影响.如果您struct使用a 引用a let,则无法更改其属性或调用其任何mutating func方法.

使用let/ varwith collections非常类似于可变/不可变的Foundation集合:如果将数组分配给a let,则无法更改其内容.如果您引用字典let,则无法添加/删除键/值对或为键指定新值 - 它确实是不可变的.如果要分配到,附加或以其他方式改变数组或字典,则必须使用声明var.

(在Xcode 6 beta 3之前,Swift数组有一个奇怪的值和参考语义组合,并且在分配给a时部分可变let- 现在已经消失了.)

  • 这很奇怪,你可以改变用let定义的数组,但你不能改变用let定义的字典. (2认同)

wco*_*ran 5

最好从静态单一赋值let(SSA)的角度来考虑——每个 SSA 变量都只被赋值一次。在像 lisp 这样的函数式语言中,你(通常)不使用赋值运算符——名称与值只绑定一次。例如,名称和以下名称仅绑定到一个值一次(每次调用):yz

func pow(x: Float, n : Int) -> Float {
  if n == 0 {return 1}
  if n == 1 {return x}
  let y = pow(x, n/2)
  let z = y*y
  if n & 1 == 0 {
    return z
  }
  return z*x
}
Run Code Online (Sandbox Code Playgroud)

这有助于生成更正确的代码,因为它强制执行不变性并且没有副作用。

以下是命令式程序员如何计算 5 的前 6 次方:

var powersOfFive = Int[]()
for n in [1, 2, 3, 4, 5, 6] {
    var n2 = n*n
    powersOfFive += n2*n2*n
}
Run Code Online (Sandbox Code Playgroud)

显然n2is 是一个循环不变式,所以我们可以使用let

var powersOfFive = Int[]()
for n in [1, 2, 3, 4, 5, 6] {
    let n2 = n*n
    powersOfFive += n2*n2*n
}
Run Code Online (Sandbox Code Playgroud)

但真正的函数式程序员会避免所有副作用和突变:

let powersOfFive = [1, 2, 3, 4, 5, 6].map(
    {(num: Int) -> Int in
        let num2 = num*num
        return num2*num2*num})
Run Code Online (Sandbox Code Playgroud)