一尘不染

“后卫让foo = foo”何时合法?

swift

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

链接: 为什么后卫不让foo = foo有效?

当我编写该问题时,以下代码将无法编译,并显示“定义与先前值冲突”的错误:

//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在警卫之前是可选的,而在包装后是未包装的可选的:

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

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

我很高兴这个构造现在可以按我希望的方式工作,但是对于 为什么 现在合法以及更改发生的时间感到困惑。

是否有人知道对语言定义的最新更改,使此构造在以前从未有过的地方起作用?


阅读 270

收藏
2020-07-07

共1个答案

一尘不染

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

2020-07-07