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

时间:2016-11-01 03:13:22

标签: swift

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

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)")
}

为什么不呢?

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

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

P.S。:我意识到这个问题并不适合这个网站。我很乐意就这个问题的哪个地方提出建议。

1 个答案:

答案 0 :(得分:10)

你不能这样做的原因:

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)")
    }
}

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

来自评论:

  

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

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

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?了解有关此主题的更多信息。