`guard let foo = foo`什么时候变得合法了?

When did `guard let foo = foo` become legal?

早在 2016 年 11 月,我发布了一个问题,询问为什么我不能使用 guard 创建一个使用与可选变量相同名称的变量的未包装版本,就像你可以使用 if let:

Link:

当我写那个问题时,下面的代码将无法编译并出现错误 "Definition conflicts with previous value":

//Test of using guard to create an unwrapped version of a var, like if let
func guardTest(_ viewController: UIViewController?) -> UIViewController? {
  // Check if the current viewController exists
  print(String(describing: viewController))
  guard let viewController = viewController else {
    return nil
  }
  print(String(describing: viewController))

  return viewController
}

但是,我只是在工作中发现了一些执行此操作的代码,现在它可以毫无怨言地进行编译,并且可以执行我想要的操作!当 运行 时,打印语句显示 foo 是守卫之前的可选项,并且是未包装的可选项:

viewController = Optional(<TrochoidDemo.ViewController: 0x7ff16a039a00>)
viewController = <TrochoidDemo.ViewController: 0x7ff16a039a00>

(我在我最新的开源项目中添加了测试函数 guardTest(_:),如果你想尝试的话。可以在 Github https://github.com/DuncanMC/TrochoidDemo)

我很高兴这个构造现在可以按照我的意愿工作,但对为什么它现在合法以及何时发生变化感到困惑。

是否有人知道最近对语言定义的更改使得此构造在以前无法工作的地方工作?

TL;DR

guard let foo = foo 是合法的,如果 foo 是在另一个范围内定义的。


您的链接问题中的示例:

func test()
{
  let a: Int? = 1

  guard let a = a else{
    return
  }
  print("a = \(a)")
}

仍然不起作用,因为 guard 语句试图在同一范围内创建另一个变量 a

这个例子:

//Test of using guard to create an unwrapped version of a var, like if let
func guardTest(_ viewController: UIViewController?) -> UIViewController? {
  // Check if the current viewController exists
  print(String(describing: viewController))
  guard let viewController = viewController else {
    return nil
  }
  print(String(describing: viewController))

  return viewController
}

工作原因与此相同:

func test(a: Int)
{
    print(type(of: a))  // Int

    let a = 3.14

    print(type(of: a))  // Double
}

函数的参数在不同的范围内定义,因此Swift允许您创建一个同名的局部变量。