在Swift REPL中,我可以使用let
分配常量,但为什么我可以稍后使用var
修改它?
let name = "al"
var name = "bob"
斯威夫特在这里没有抱怨,但这不是一个常数吗?
答案 0 :(得分:3)
重新声明变量(在同一范围内)在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:
...但在REPL交互式环境中,能够轻松进行更改非常有用。 REPL专门设计时考虑到了这种便利......
...较新的定义替换了所有后续引用的现有定义
注意:您必须单独输入行。如果您复制那些 两行进入粘贴缓冲区,启动REPL并粘贴 他们用 Cmd V 然后结果是
$ 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" ^
答案 1 :(得分:1)
REPL允许在变体或让后重新声明变体或让,如果在单独的行中输入。
此示例在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中重新删除和更改。
但是REPL不允许在一行中(用分号)或如先前的回答中所述在粘贴的块中进行重新声明:
4> let y = 30; let y=20
error: repl.swift:18:17: error: invalid redeclaration of 'y'
还请注意,调用 / usr / bin / swift 的 shebang / 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()内部,仍然是范围内并被捕获的第一个变量xx = 10。这就是捕获的工作方式。但是请注意,捕获的变量在REPL提示符下不再存在。重新声明捕获的变量不会自动重新捕获它。
有时候,我会使用REPL来研究错误或语言构造,因此很高兴知道这些细微之处,因为它们可能导致您的代码中发生什么混乱,或者可能导致误解。语言。
REPL函数重载和var / let重新声明在前面的答案中提到的博客文章中都有解释,请参见https://developer.apple.com/swift/blog/?id=20
我认为我已经总结了以前的答案和评论中的一些发现,并添加了更多详细信息。