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

Dun*_*n C 7 swift

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

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

  if let a = a {
    print("a = \(a)")
  } 
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

  guard let requiredA = a else{
    return
  }
  print("a = \(requiredA)")
}
Run Code Online (Sandbox Code Playgroud)

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

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

  guard let a = a else{
    return
  }
  print("a = \(a)")
}
Run Code Online (Sandbox Code Playgroud)

为什么不?

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

为什么我不能将可选项映射到当前作用域的其余部分的同名变量/常量?

PS:我意识到这个问题不适合这个网站.我愿意接受有关这个问题哪个地方更好的建议.

vac*_*ama 10

你不能这样做的原因:

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

  guard let a = a else{
    return
  }
  print("a = \(a)")
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

    let a = a!
}
Run Code Online (Sandbox Code Playgroud)

与之相比:

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

    if let a = a {
        print("a = \(a)")
    }
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,新的变量a这是一个Int只存在于新范围if的然后子句,所以此工程.


来自评论:

但是我告诉你,关闭括号后的代码部分和封闭范围的末尾实际上是一个内部范围.

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

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)")
}
Run Code Online (Sandbox Code Playgroud)

它的美妙之guard处在于它不会创建新的范围,并且当您反复使用解包选项时(并在此过程中创建新范围)时,您将避免创建死亡金字塔if let.


看到后续问题 什么时候警卫让foo = foo变得合法?有关此主题的更多见解.