Reputation: 2098
Question 1: in guard let self = self else { return }
, first self
and second self
are same, why it can be compiled successfully? Because normal let self = self
will be compiled with errors.
Question 2: Even I found guard let self else { return }
in some projects, why it can be compiled successfully?
Upvotes: -2
Views: 130
Reputation: 438152
The guard let
is an “optional binding” pattern. It is like the if let
optional binding discussed in The Swift Programming Language: Optional Binding, except that guard let
affords an “early exit”. Consider:
guard let self else {
// if `self` was `nil`, then just exit
return
}
// otherwise, if we got here, then `self` was not `nil`, and it is
// no longer an optional from this point on
This is a variation of the if let
optional binding pattern discussed in The Swift Programming Language. For example:
if let self {
// you will only get here if `self` was not `nil`;
// inside this block, `self` is longer an optional
…
}
// but that optional binding only applies within the block above; once you
// get here, you’re dealing with an optional reference to `self` again
You contrasted that with a simple let self = self
, which performs no optional binding: That will undoubted generate compilation errors regarding the misuse of the reserved keyword, self
, as well as any subsequent code that was expecting self
to no longer be an optional. You can only use self
like this from within an optional binding pattern, such as the if let
or guard let
patterns shown above (or while let
, which is less common).
A few links for your reference, discussing the evolution of the syntax associated with optional binding of self
:
SE-0079 discusses the use of if let self = self {…}
pattern:
The proposed solution entails allowing
self
to be upgraded from a weak reference to a strong reference using optional binding.
That proposal replaces the legacy pattern of …
if let strongSelf = self { … }
… with something that avoids the confusion of introducing a separate variable name, reducing it to:
if let self = self { … }
That was introduced in Swift 4.2.
The shortening of this syntax is contemplated in SE-0345, which says:
Optional binding using
if let foo = foo { … }
, to create an unwrapped variable that shadows an existing optional variable, is an extremely common pattern. This pattern requires the author to repeat the referenced identifier twice, which can cause these optional binding conditions to be verbose, especially when using lengthy variable names. We should introduce a shorthand syntax for optional binding when shadowing an existing variable:let foo: Foo? = … if let foo { // `foo` is of type `Foo` }
The pattern works for self
, too. Thus, the example in my first point is reduced to:
if let self { … }
That was introduced in Swift 5.7.
As an aside, SE-0365, in its discussion of “implicit self”, shows lots of examples of the if let
and guard let
patterns, e.g.:
guard let self else { … }
Upvotes: 2
Reputation: 2315
By writing let self = self
you declare a variable self
and give it a value of self
(i.e., a reference to the instance of the object that the line is called inside).
Swift allows variable shadowing, so it's legal to create a local variable self
that shadows the identifier self
from the outer scope.
There's one caveat, though: self
is also a special word in Swift and can't be used as a variable name (the compiler emits the error "Keyword 'self' cannot be used as an identifier here")... unless you apply an escaping technique: let `self` = self.
On the other hand, guard
doesn't require this kind of escaping. I suppose that since the idiom guard let self = self
is so common, language developers decided to make an exception for it to avoid some boilerplate code.
In later versions of the language, they also introduced a shorthand syntax for unwrapping optional values: guard let self
. In fact you can use it with any optional variable to unwrap it: guard let anyOptional
.
As for why guard let self else { return }
cannot be compiled in some places, it's impossible to say without more details, but I have two assumptions:
self
itself might be unavailable in the context (i.e., the code is written outside of an instance of an object, e.g., in the global scope).Upvotes: 0