【问题标题】:How exactly does the "let" keyword work in Swift?“let”关键字在 Swift 中究竟是如何工作的?
【发布时间】:2014-07-23 01:41:43
【问题描述】:

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

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

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

【问题讨论】:

  • 这似乎意味着您不能更改 var,但是如果 var 指向一个对象,您应该能够以与对象在 a 范围内访问相同的方式对对象进行更改堵塞。 IOW,它是一个 var 指向一个可变数组,数组中的值应该可以改变。
  • 如果您来自 C#,那么如果允许的话,它将与“readonly var”具有相同的含义。或 F# 中的“让”。
  • 是的,您仍然可以修改属性,具体取决于它们的配置方式。这与 JavaScript 中的 const 类似。除非它被冻结/密封或标记为不可写,否则通常仍然可以修改字段。

标签: constants swift


【解决方案1】:

let 有点像 C 中的 const 指针。如果引用带有 let 的对象,则可以更改对象的属性或调用其上的方法,但不能将不同的对象分配给那个标识符。

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

let/var 与集合一起使用很像可变/不可变的基础集合:如果将数组分配给let,则无法更改其内容。如果您使用let 引用字典,则无法添加/删除键/值对或为键分配新值——它确实是不可变的。如果你想给数组或字典中的下标赋值、追加或以其他方式改变,你必须用var声明它。

(在 Xcode 6 beta 3 之前,Swift 数组具有奇怪的值和引用语义组合,并且在分配给 let 时是部分可变的——现在已经不存在了。)

【讨论】:

  • 你知道行为是否与NSDictionary/NSMutableDictionary一致吗?
  • 以什么方式一致?
  • 嗯……我想我应该问一下:有什么明显的不一致吗? (性能、方法等)
  • 这很奇怪,你可以改变用let定义的数组,但你不能改变用let定义的字典。
  • 更新:从 XCode 6 beta 3 开始,你也不能替换用 let 定义的数组中的值,所以现在看起来更一致了。来源:functionwhatwhat.com/…
【解决方案2】:

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

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

【讨论】:

    【解决方案3】:

    最好将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
    }
    

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

    以下是命令式程序员如何计算 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})
    

    【讨论】:

    • Lisp 肯定是有赋值的,值可以多次赋值给一个变量。
    • 是的,Lisp 确实允许赋值(例如 setf),但函数式程序员只在真正需要时才使用它……这确实发生了。
    【解决方案4】:


    Swift 使用两种基本技术来存储值以供程序员使用名称访问:letvar。如果您永远不会更改与该名称关联的值,请使用 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.
    

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

    【讨论】:

    • 对不起,但我认为您的 Let and Collections 示例与数组示例不正确,因为 a[0] = 0 不允许可变性,所以这不行。跨度>
    【解决方案5】:

    Swift 属性:

    Swift Properties official documentation

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

    例子:

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

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

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

    【讨论】:

      【解决方案6】:

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

      其实在swift中没有常量的概念

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

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

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

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

      在 C# 术语中,您可以将“let”视为"readonly" 变量

      Swift "let" == C# "readonly"

      【讨论】:

        猜你喜欢
        • 2020-10-25
        • 2023-04-01
        • 2011-06-26
        • 2021-08-15
        • 2012-06-08
        • 2011-10-11
        • 2013-07-05
        • 1970-01-01
        相关资源
        最近更新 更多