let 和 var Swift REPL 中 const 的无效重新声明

let and var Invalid redeclaration of const in Swift REPL

在Swift REPL中我可以用let赋值一个常量,但为什么我以后可以用var修改它?

let name = "al"

var name = "bob"

Swift 并不是在抱怨,但是 name 不是常量吗?

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

$ cat test.swift 
let name = "al"
var name = "bob"

$ swiftc test.swift 
test.swift:2:5: error: invalid redeclaration of 'name'
var name = "bob"
    ^
test.swift:1:5: note: 'name' previously declared here
let name = "al"
    ^

然而,Swift REPL 的行为不同:

$ swift
Welcome to Apple Swift version 3.1 (swiftlang-802.0.53 clang-802.0.42). Type :help for assistance.
  1> let name = "al" 
name: String = "al"
  2> var name = "bob"
name: String = "bob"

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

... but in the REPL interactive environment it’s useful to be able to easily make changes. The REPL was specifically designed with this kind of convenience in mind ...

... The newer definition replaces the existing definition for all subsequent references


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

$ swift
Welcome to Apple Swift version 3.1 (swiftlang-802.0.53 clang-802.0.42). Type :help for assistance.
  1> let name = "al" 
  2. var name = "bob"
error: repl.swift:2:5: error: invalid redeclaration of 'name'
var name = "bob"
    ^

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

$ swift
Welcome to Apple Swift version 3.1 (swiftlang-802.0.53 clang-802.0.42). Type :help for assistance.
  1> let name = "al" ; var name = "bob"
error: repl.swift:1:23: error: invalid redeclaration of 'name'
let name = "al" ; var name = "bob"
                      ^

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 中重新 let 和重新 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重新声明在前面的回答中提到的博客post中都有解释,参见https://developer.apple.com/swift/blog/?id=20

我想我应该总结一下之前答案和评论的一些发现,并添加更多细节。