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

时间:2017-07-23 06:43:59

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

在Swift REPL中,我可以使用let分配常量,但为什么我可以稍后使用var修改它?

let name = "al"

var name = "bob"
斯威夫特在这里没有抱怨,但这不是一个常数吗?

2 个答案:

答案 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

有两个函数,并且两个函数具有相同的名称。一个接受一个I​​nt,另一个接受一个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

我认为我已经总结了以前的答案和评论中的一些发现,并添加了更多详细信息。