【问题标题】:let and var Invalid redeclaration of const in Swift REPLlet 和 var 在 Swift REPL 中重新声明 const 无效
【发布时间】:2017-12-28 23:00:51
【问题描述】:

在 Swift REPL 中,我可以使用 let 分配一个常量,但为什么我以后可以使用 var 对其进行修改?

let name = "al"

var name = "bob"

斯威夫特在这里没有抱怨,但名字不是一个常数吗?

【问题讨论】:

  • 还有别的吗?因为这两行单独为我编译(“错误:'name'的无效重新声明”
  • 我在 Mac 终端应用程序上...只需输入 swift 并查看
  • error: repl.swift:3:5: error: invalid redeclaration of 'name'...
  • 我的 Swift 3.1 REPL 确实没有产生错误,但它不能在 Xcode 中编译。
  • @l'L'l:现在变得有趣了:如果您分别粘贴行,它会起作用。

标签: swift variables constants read-eval-print-loop


【解决方案1】:

重新声明一个变量(在同一范围内)在 Swift 中是无效的:

$ 猫 test.swift 让名称=“al” 变量名称 = “鲍勃” $ swiftc test.swift test.swift:2:5:错误:“名称”的无效重新声明 变量名称 = “鲍勃” ^ test.swift:1:5: 注意:'name' 之前在这里声明过 让名称=“al” ^

但是,Swift REPL 的行为有所不同:

$ 迅速 欢迎使用 Apple Swift 3.1 版 (swiftlang-802.0.53 clang-802.0.42)。输入 :help 寻求帮助。 1>让名称=“al” 名称:字符串 = “al” 2> 变种名称 = “鲍勃” 名称:字符串 = “鲍勃”

这是故意的,如中所述 Redefining Everything with the Swift REPL:

...但是在 REPL 交互式环境中,能够轻松进行更改很有用。 REPL 专门设计时考虑到了这种便利性......

...较新的定义替换所有后续引用的现有定义


注意:你必须单独输入这些行。如果你复制那些 两行进入粘贴缓冲区,启动 REPL 并粘贴 他们用 CmdV 那么结果是

$ 迅速 欢迎使用 Apple Swift 3.1 版 (swiftlang-802.0.53 clang-802.0.42)。输入 :help 寻求帮助。 1>让名称=“al” 2. 变量名 = “鲍勃” 错误:repl.swift:2:5:错误:“名称”的无效重新声明 变量名称 = “鲍勃” ^

显然这两个语句现在在同一范围内进行评估 (第二行有继续提示)并产生错误。 同一行中的两个语句也会发生同样的情况:

$ 迅速 欢迎使用 Apple Swift 3.1 版 (swiftlang-802.0.53 clang-802.0.42)。输入 :help 寻求帮助。 1> 让名称 = "al" ;变量名称 = “鲍勃” 错误:repl.swift:1:23:错误:“名称”的无效重新声明 让名称=“人”;变量名称 = “鲍勃” ^

【讨论】:

  • 好的,明白了,谢谢,但它仍然有点...棘手,无论如何...尤其是对于新手...
  • 很好地抓住了这种行为......很难理解它背后的概念,特别是如果你习惯了 Python 在交互模式下的工作方式。现在确实完全可以理解为什么它的行为与之前观察到的一样。
  • @l'L'l:是的,有人可能会争辩说 REPL 应该以不同的方式处理每个 语句,这可能是一个错误。
  • 当然,我已经习惯了 Python REPL,它的行为与 Python IDLE 相同,但正如他们所说,我们总是会学到新的东西。感谢谁解释了这种奇怪的行为。
  • @A.N.Other:不客气! – 但我建议您稍微修改一下您的问题,并明确说明使用了 REPL。
【解决方案2】:

REPL 允许在 var 或 let 之后重新声明 var 或 let,如果在单独的行中输入

这个例子在 REPL 中是允许的,但在 swiftc 中是不允许的:

$ swift
Welcome to Apple Swift version 5.0.1 (swiftlang-1001.0.82.4 clang-1001.0.46.4).
Type :help for assistance.
 1> var x = 10
x: Int = 10
 2> let x = 20
x: Int = 20
 3> let x = 30 // allowed in REPL
x: Int = 30

如果短语逐行输入,您可以在 REPL 中 re-let 和 re-var。

但是 REPL 不允许在一行中重新声明(使用分号),或者如之前的回答中提到的,在粘贴的块中:

 4> let y = 30; let y=20
error: repl.swift:18:17: error: invalid redeclaration of 'y'

还要注意,调用 /usr/bin/swiftshebang/hashbang 脚本将使用 swiftc 而不是 REPL。可能令人困惑的是,swiftc 和 swift 以及 REPL 都是同一个/usr/bin/swift

#!/usr/bin/swift
let x = 10
let x = 20 // not allowed

函数的重新声明以同样的方式被允许:

> func x() {} 
> func x() {} // allowed in REPL
> func y() {}; func y() {}  
error: repl.swift:7:19: error: invalid redeclaration of 'y()'

正如我们所料,函数重新声明适用于完整的函数签名。声明重载将声明一个新函数,该函数将与同名但具有不同参数的现有函数一起存在。这意味着重载不一定会重新声明以前的同名函数。

让我们声明一些重载函数,让我们在一行中完成所有这些来证明它们在 REPL 中是允许的。

> func y(_:Int) {print("y Int")}; func y(_:String) {print("y String")};
> y(3) 
y Int
> y("Y") 
y String

有两个函数,并且都具有相同的名称。一个采用 Int,另一个采用 String。让我们重新声明一个 Int:

func y(_:Int) {print("y Int new")};
> y(3)
y Int new

就是这样:输出显示它被重新声明了。

如果您不习惯捕获,事情可能会变得混乱(或危险)。观察当范围内的变量被捕获时会发生什么:

> var xx=10;
xx: Int = 10
> func x(){print(xx)}; x()
10

这很直观。但是当我们重新声明捕获的变量时会发生什么:

> var xx=10; x() 
10
xx: Int = 10

一切都还好吗?不,等等……

> xx=20; x()
10

为什么是 10 而不是 20?在 x() 内部,它仍然是第一个 var xx=10 在范围内并被捕获。这就是捕获的工作方式。但请注意,捕获的变量在 REPL 提示符下不再存在。重新声明捕获的变量不会自动重新捕获它。

有时我使用 REPL 来挖掘错误或语言结构,最好了解这些细微之处,因为它们可能会导致您对代码中发生的事情感到困惑,或者可能导致对代码的误解语言。

REPL 函数重载和 var/let 重新声明都在前面回答中提到的博文中有解释,见https://developer.apple.com/swift/blog/?id=20

我想我会总结之前的答案和 cmets 中的一些发现,并添加更多细节。

【讨论】:

    猜你喜欢
    • 2018-08-15
    • 1970-01-01
    • 1970-01-01
    • 2020-11-04
    • 1970-01-01
    • 1970-01-01
    • 2021-09-21
    • 2016-08-19
    相关资源
    最近更新 更多