【问题标题】:When did `guard let foo = foo` become legal?`guard let foo = foo` 什么时候变得合法了?
【发布时间】:2017-06-10 18:50:34
【问题描述】:

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

链接: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
}

但是,我刚刚发现了一些可以执行此操作的代码,它现在可以毫无怨言地编译并执行我希望它执行的操作!运行时,打印语句显示 foo 在保护之前是可选的,而在之后是未包装的可选:

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

(如果你想尝试一下,我在我最新的开源项目中添加了测试功能guardTest(_:)。它可以在Github上获得,地址是https://github.com/DuncanMC/TrochoidDemo

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

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

【问题讨论】:

  • 这仍然无法在函数中重新定义另一个局部变量。这似乎与 Swift 允许您创建一个与函数的输入参数同名的局部变量这一事实有关。我不知道这是否一直有效,但 var a = a 现在是将输入参数转换为 var 的方法,因为您不能再将 var 放入函数签名中。
  • 好的,为什么投反对票?如果您认为我的问题很糟糕,请解释原因。
  • 我当然投了赞成票。任何挑战我认为我理解得很好的问题在我的书中都是一个很好的问题。我有点希望在否决或至少对他人的建设性评论进行投票时强迫您发表(建设性的,希望如此)评论。

标签: swift guard


【解决方案1】:

TL;DR

如果foo 在另一个范围内定义,guard let 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 允许你创建一个同名的局部变量。

【讨论】:

  • 好的,有道理。感谢您清理它。您的示例合法似乎很奇怪,因为您的 let a = 3.14 使参数无法访问。
  • 这种情况经常发生。局部变量对封闭范围隐藏其他变量。让我感到困惑的是为什么第一个 print(type(of: a)) 没有给出错误,但在这种情况下却出现了 let a = 3 func test() { print(type(of: a)) let a = 3.14 print(type(of: a)) }
  • 我认为函数的参数在本地范围内,而不是在封闭范围内。这个讨论清楚地表明参数实际上被认为来自封闭范围。因此,var a=a 在 a 是参数时是合法的,因为它从封闭范围中获取常量并将其重新定义为当前范围中的变量。
  • 函数参数的作用域和for 循环中创建的变量的作用域是相同的。考虑:for i in 1...3 { print(i); let i = 3.14; print(i) }
  • 在我看来,Swift 中有一条规则,就像 C 语言一样,大括号定义了一个新的范围,包括函数大括号和 for..in 语句周围的语句大括号。 (大部分是显而易见的。对于函数,参数是在大括号外声明的,因此参数被认为是函数体的外层范围。)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-06-12
  • 2010-12-12
  • 1970-01-01
  • 2017-06-23
  • 1970-01-01
  • 1970-01-01
  • 2012-10-02
相关资源
最近更新 更多