Why isn't guard let foo = foo valid?

后端 未结 1 1049
日久生厌
日久生厌 2020-12-06 18:09

In Swift, you can use if let optional binding to unwrap an optional into a constant or variable with the same name:

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

  if let         


        
相关标签:
1条回答
  • 2020-12-06 18:22

    The reason you can't do this:

    func test()
    {
      let a: Int? = 1
    
      guard let a = a else{
        return
      }
      print("a = \(a)")
    }
    

    is because guard creates the new variable in the same scope, thus you have two variables called a in the same scope. One is an Int and the other is an Int?. That is not allowed.

    The error that you get Definition conflicts with previous value is exactly the same as if you had done this:

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

    Compare that with:

    func test()
    {
        let a: Int? = 1
    
        if let a = a {
            print("a = \(a)")
        }
    }
    

    In this case, the new variable a which is an Int exists only in the new scope of the if's then clause, so this works.


    From the comments:

    But I submit to you that the section of code after the closing brace and to the end of the enclosing scope is actually an inner scope.

    I can understand that you would like it to be so, but it isn't. If that were the case, then you could do this, but it too gives an error:

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

    The beauty of guard is that it doesn't create new scopes and you avoid creating the pyramid of death that results when you repeatedly use if let to unwrap optionals (and in the process create new scopes).


    See the follow-up question When did guard let foo = foo become legal? for more insight on this topic.

    0 讨论(0)
提交回复
热议问题