With optional chaining, if I have a Swift variable
var s: String?
s might contain nil, or a String wrapped in an Optional. So, I tried this to get its length:
let count = s?.characters?.count ?? 0
However, the compiler wants this:
let count = s?.characters.count ?? 0
My understanding of optional chaining is that, once you start using ?.
in a dotted expression, the rest of the properties are made optional and are typically accessed by ?.
, not .
.
So, I dug a little further and tried this in the playground:
var s: String? = "Foo"
print(s?.characters)
// Output: Optional(Swift.String.CharacterView(_core: Swift._StringCore(_baseAddress: 0x00000001145e893f, _countAndFlags: 3, _owner: nil)))
The result indicates that s?.characters
is indeed an Optional instance, indicating that s?.characters.count
should be illegal.
Can someone help me understand this state of affairs?
When you say:
My understanding of optional chaining is that, once you start using
?.
in a dotted expression, the rest of the properties are made optional and are typically accessed by?.
, not.
.
I would say that you are almost there.
It’s not that all the properties are made optional, it’s that the original call is optional, so it looks like the other properties are optional.
characters
is not an optional property, and neither is count
, but the value that you are calling it on is optional. If there is a value, then the characters
and count
properties will return a value; otherwise, nil
is returned. It is because of this that the result of s?.characters.count
returns an Int?
.
If either of the properties were optional, then you would need to add ?
to it, but, in your case, they aren’t. So you don’t.
Edited following comment
From the comment:
I still find it strange that both
s?.characters.count
and(s?.characters)?.count
compile, but(s?.characters).count
doesn't. Why is there a difference between the first and the last expression?
I’ll try and answer it here, where there is more room than in the comment field:
s?.characters.count
If s
is nil, the whole expression returns nil
, otherwise an Int
. So the return type is Int?
.
(s?.characters).count // Won’t compile
Breaking this down: if s
is nil
, then (s?.characters)
is nil
, so we can’t call count
on it.
In order to call the count
property on (s?.characters)
, the expression needs to be optionally unwrapped, i.e. written as:
(s?.characters)?.count
Edited to add further
The best I can get to explaining this is with this bit of playground code:
let s: String? = "hello"
s?.characters.count
(s?.characters)?.count
(s)?.characters.count
((s)?.characters)?.count
// s?.characters.count
func method1(s: String?) -> Int? {
guard let s = s else { return nil }
return s.characters.count
}
// (s?.characters).count
func method2(s: String?) -> Int? {
guard let c = s?.characters else { return nil }
return c.count
}
method1(s)
method2(s)
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments