什么时候`警卫让foo = foo`变得合法?

时间:2017-01-25 14:31:18

标签: swift guard

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

链接: Why isn't guard let foo = foo valid?

当我写下这个问题时,下面的代码将无法编译,错误“定义与先前值冲突”:

//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
}

但是,我刚刚在工作中找到了一些代码来执行此操作,现在它可以在没有投诉的情况下进行编译,并完成我想要它做的事情!运行时,print语句显示foo在guard之前是可选的,而在一个uncrapped可选之后:

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

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

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

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

1 个答案:

答案 0 :(得分:9)

<强> 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允许您创建一个具有相同名称的局部变量。