【问题标题】:Why isn't guard let foo = foo valid?为什么 guard let foo = foo 无效?
【发布时间】:2016-11-01 03:13:21
【问题描述】:

在 Swift 中,您可以使用 if let 可选绑定将可选项解包为具有相同名称的常量或变量:

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

  if let a = a {
    print("a = \(a)")
  } 
}

对于 if let 语句中的所有内容,可选的 a 被解包为常规 int。

同样,我可以使用一个guard语句来达到类似的效果

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

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

但是,我不能使用这样的代码:guard let a = a else

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

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

为什么不呢?

在保护语句中,如果保护语句的条件失败,则执行 else 子句并退出当前作用域。如果条件成功,则从保护语句的右大括号到当前范围的末尾创建一个新的变量/常量。

为什么我不能在当前范围的其余部分使用相同的技巧将可选映射到具有相同名称的变量/常量?

P.S.:我知道这个问题并不适合这个网站。我愿意接受有关在哪里解决这个问题的建议。

【问题讨论】:

  • 在我看来 if 方式在不同的范围内创建了两个变量,这很好,而 guard 方式将在同一范围内创建两个同名的变量,这将是一个奇怪的特殊情况并使变量解析规则复杂化以允许它。不过,我猜;我不认识斯威夫特。

标签: swift


【解决方案1】:

你不能这样做的原因:

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

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

是因为guard 在同一范围内创建了新变量,因此您在同一范围内有两个名为a 的变量。一个是Int,另一个是Int?。这是不允许的。

您得到的错误 Definition conflict with previous value 与您执行此操作时完全相同:

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

    let a = a!
}

比较一下:

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

    if let a = a {
        print("a = \(a)")
    }
}

在这种情况下,Int 的新变量 a 仅存在于 if 的 then 子句的新范围内,所以这是可行的。


来自cmets:

但是我向你提交了右括号后面的代码部分 并且到封闭范围的末尾实际上是一个内部范围。

我可以理解您希望它是这样,但事实并非如此。如果是这种情况,那么你可以这样做,但它也会报错:

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

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

    let a = 5  // Definition conflicts with previous value

    print("a = \(a)")
}

guard 的美妙之处在于它不会创建新的作用域,并且您可以避免创建死亡金字塔,当您重复使用 if let 解开可选选项时(以及在此过程中)创建新范围)。


查看后续问题 When did guard let foo = foo become legal? 了解有关此主题的更多信息。

【讨论】:

  • 但是我向你提出,在右大括号之后和封闭范围末尾的代码部分实际上是一个内部范围。如果您创建一个新的变量/常量,它会从该点一直存在到当前范围的末尾。这与if let 有何不同,在语句的主体内部,a 的本地定义覆盖了外部定义?
  • 它与 if let 不同,因为 if let 后面的 { } if let 创建了一个新范围。 guard 的美妙之处在于您没有{ },从而避免了新作用域的死亡金字塔。
  • @DuncanC if let 完全不同。试试这个:if let b = a { ... } let b = 4。第二个b 很好,因为if let 中的b 不再在范围内。
  • 是的,我想这是有道理的。它使您使用的模式与if let 不同,并导致一些尴尬的命名,例如我的示例中的reqiredA
  • 当然可以,但这最终会导致嵌套级别不断增加,并且不会像 guard 那样为您提供“黄金路径”优势
猜你喜欢
  • 1970-01-01
  • 2017-06-10
  • 2019-02-10
  • 1970-01-01
  • 1970-01-01
  • 2010-12-12
  • 1970-01-01
  • 1970-01-01
  • 2017-06-23
相关资源
最近更新 更多