user2930077
user2930077

Reputation: 135

How to gracefully use guard or if let in swift

how to get a first item in empty list to use guard let or if let.

For example, I have an empty list and I would like to get gracefully first item in list like here, but it looks like:

var empty_array: [Int] = []
guard let first = empty[0] as? Int else{
    // do something
}
// after operation first should be nil

And my code crashes because first item missed in list and I would like to get result of first item that will be nil. How to do this?

UPDATED: to get first item needs use

guard let first = empty.first as? Int else{
    // do something
}

But what about second or third item?

Upvotes: 0

Views: 1920

Answers (3)

JeremyP
JeremyP

Reputation: 86651

The reason it crashes is because getting an element from an array using a subscript does not return an optional. If no element exists at the index it simply crashes with index out of bounds. This is in contrast to dictionaries where subscript access returns an optional. The rationale behind this design decision is that, for arrays, unwrapping the optional every time would be a right pain, especially as all you have to do is test the index is in 0 ..< array.count.

Your guard statement tries to access an array element that does not exist, so it crashes. Also, your guard statement is the wrong way around. The block after the else is what is executed in the exceptional condition.

So, if you use empty_array.first which does return an optional, you should do this:

guard let first = empty_array.first else { return /* bail out of the function */ }

doSomething(with: first) // first is unwrapped here.

Or use if

if let first = empty_array.first
{
    doSomething(with: first) // first is unwrapped here.
}

Or you can test the index to make sure it is in range. Has the advantage of working with any index, not just zero

let index = // Some integer

guard index >= 0 && index < empty_array.count else { return }

doSomething(with: empty_array[index])

Or

guard (0 ..< empty_array.count).contains(index) else { return }

Upvotes: 0

Teetz
Teetz

Reputation: 3765

You could either

var empty: [Int] = []
guard let first = empty.first else {
// cast did fail - do any stuff to escape this func or whatever you would like to do
}
// access first here --> first is not nil 

or

var empty: [Int] = []
if let first = empty.first {
// access first here --> first is not nil 
} else {
// cast did fail - do stuff 
}

Upvotes: 1

zneak
zneak

Reputation: 138041

Use empty.first, which returns a T?.

guard let first = empty.first else {
    // do something
}

Note that the body of a guard statement must exit the parent scope. It sounds like your comments have it backwards (first is nil in the guard scope, not after it).

Upvotes: 1

Related Questions