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

时间:2014-06-02 20:45:59

标签: constants swift

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

  

在编译时不需要知道常量的值,但是必须为它赋值一次。

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

6 个答案:

答案 0 :(得分:44)

let有点像C中的const指针。如果引用带有let的对象,则可以更改对象的属性或调用方法它,但您不能为该标识符分配不同的对象。

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

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

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

答案 1 :(得分:4)

最好根据静态单一分配(SSA)来考虑let - 每个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
}

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

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

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

显然n2是一个循环不变量,所以我们可以使用let代替:

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

但真正有功能的程序员会避免所有的副作用和突变:

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

答案 2 :(得分:3)


Swift使用两种基本技术来存储程序员使用名称访问的值: let var 。如果您永远不会更改与该名称关联的值,请使用 let 。如果您希望该名称引用一组不断变化的值,请使用 var

let a = 5  // This is now a constant. "a" can never be changed.
var b = 2  // This is now a variable. Change "b" when you like.

常量引用的值永远不会改变,但是如果它是类的实例,则常量引用的值可以改变。

let a = 5
let b = someClass()
a = 6  // Nope.
b = someOtherClass()  // Nope.
b.setCookies( newNumberOfCookies: 5 )  // Ok, sure.

和收藏


将数组分配给常量时,无法再从该数组中添加或删除元素。但是,任何该数组元素的值仍可能会更改。

let a = [1, 2, 3]
a.append(4)  // This is NOT OK. You may not add a new value.
a[0] = 0     // This is OK. You can change an existing value.

不能以任何方式更改分配给常量的字典。

let a = [1: "Awesome", 2: "Not Awesome"]
a[3] = "Bogus"             // This is NOT OK. You may not add new key:value pairs.
a[1] = "Totally Awesome"   // This is NOT OK. You may not change a value.

这是我对这个主题的理解。请在需要的地方纠正我。对不起,如果问题已经得到解答,我这样做的部分原因是为了帮助自己学习。

答案 3 :(得分:2)

首先," let关键字定义一个常量" 让来自C#background(就像我)的初学者感到困惑。在阅读了许多Stack Overflow答案后,我得出结论

  

实际上,在swift中没有常数的概念

常量是在编译时解析的表达式。对于C#和Java,必须在声明期间分配常量:

public const double pi = 3.1416;         // C#
public static final double pi = 3.1416   // Java

Apple doc(定义常量使用" let"):

  

在编译时不需要知道常量的值,但是必须只为该值赋值一次。

在C#术语中,你可以想到"让"作为"readonly"变量

  斯威夫特"让" == C#" readonly"

答案 4 :(得分:0)

使用Swift的let关键字,F#用户会感到宾至如归。 :)

在C#术语中,如果允许该构造,则可以将“let”视为“readonly var”,即:只能在声明点绑定的标识符。

答案 5 :(得分:0)

Swift属性:

Swift Properties official documentation

  

最简单的形式是,存储属性是一个常量或变量,它存储为特定类或结构的实例的一部分。存储的属性可以是变量存储属性(由var关键字引入),也可以是常量存储属性(由let关键字引入)。

示例:

  

下面的示例定义了一个名为FixedLengthRange的结构,该结构描述了一系列整数,其范围长度一旦创建就无法更改:

struct FixedLengthRange {
    var firstValue: Int
    let length: Int
}
  

FixedLengthRange的实例具有名为firstValue的变量存储属性和名为length的常量存储属性。在上面的示例中,length在创建新范围时初始化,之后无法更改,因为它是一个常量属性