Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to chain multiple if-let statements using the same variable name?

Tags:

swift

Let's say I have three optional strings, string1, string2, and string3. I don't know which, if any, is not nil so I am using if-let statements, and then I want to do something with that non-nil String regardless of which one it is.

Right now, this works in Swift but is cumbersome:

if let newString = string1 {
   doSomething()
} else if let newString = string2 {
   doSomething()
} else if let newString = string3 {
   doSomething()
}

Can I do something similar to this (which gives me an error):

if let newString = string1 || let newString = string2 || let newString = string3 {
   doSomething()
}
like image 624
Kevin2566 Avatar asked Jul 25 '19 18:07

Kevin2566


2 Answers

Solution 1 :

if let newString = [string1, string2, string3].compactMap({$0}).first {
    print(newString)
}

The compactMap function will generate an array of non-null values and you'll be taking the first value of it

Solution 2 :

if let newString = [string1, string2, string3].first(where: {$0 != nil}) {
  print(newString)
}

Note: As suggested by @Connor and the brilliant solutions by @vacawama, the above solution would generate a double optional ( The first optional coming from the array of optionals and then the first function contributing to the second optional). This can be fixed by either:

  1. if let newString = [str1, str2, str3].first(where: {$0 != nil}) as? String {

  2. if let newString = [str1, str2, str3].first(where: {$0 != nil}) ?? nil {

  3. if case let newString?? = [str1, str2, str3].first(where: {$0 != nil}) {

  4. if let first = [str1, str2, str3].first(where: { $0 != nil }), let newString = first

Solution 3 :

(This won't scale and quite frankly is pretty weird)

if let newString = string1 ?? string2 ?? string3 {
   print(newString)
}
like image 62
May Rest in Peace Avatar answered Sep 22 '22 10:09

May Rest in Peace


@MayRestinPeace has 3 great answers. Here's one that uses switch pattern matching and tuple matching to unwrap and bind the first non-nil String:

switch (string1, string2, string3) {
case (let newString?, _, _), (_, let newString?, _), (_, _, let newString?):
    print(newString)
default:
    print("alas! they're all nil")
}
like image 23
vacawama Avatar answered Sep 18 '22 10:09

vacawama