Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
668 views
in Technique[技术] by (71.8m points)

swift - Why isn't guard let foo = foo valid?

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 a = a {
    print("a = (a)")
  } 
}

For everything inside the if let statement, the optional a is unwrapped into a regular int.

Likewise, I can use a guard statement to achieve a similar effect

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

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

However, I can't use code like this: guard let a = a else:

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

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

Why not?

In a guard statement, if the conditional of the guard statement fails, the else clause is executed and you exit the current scope. If the conditional succeeds, a new variable/constant is created from guard statement's closing brace to the end of the current scope.

Why can't I do the same trick of mapping an optional into a variable/constant with the same name for remainder of the current scope?

P.S.: I realize this question isn't a perfect fit for this site. I'm open to suggestions as to where would be a better place for this question.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...