一尘不染

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

swift

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

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

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

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

同样,我可以使用保护语句来达到类似的效果

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子句,然后退出当前作用域。如果条件成功,则将从保护语句的右括号到当前作用域的结尾创建一个新的变量/常量。

为什么我不能做同样的技巧将可选对象映射到具有相同名称的变量/常量,以用于当前作用域的其余部分?

PS: 我知道这个问题并不适合这个网站。对于这个问题在哪里更好,我乐于接受建议。


阅读 227

收藏
2020-07-07

共1个答案

一尘不染

您无法执行此操作的原因:

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

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

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

您获得的 定义 错误 与先前的值冲突与执行此 操作完全相同:

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

    let a = a!
}

与以下内容进行比较:

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

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

在这种情况下,新的变量aan Int是仅存在于ifthen子句的新范围内,因此可以正常工作。


从评论:

但是我向您提出,右括号之后到封闭范围的末尾的代码部分实际上是一个内部范围。

我可以理解,您希望这样,但事实并非如此。如果是这种情况,那么您可以执行此操作,但同时也会出现错误:

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


2020-07-07