Mixing var and let in tuple destructuring

I currently have a function that returns a (T, U)? (actual types unimportant)
I'm trying to call the function, while unwrapping the T into a mutable variable and the U into an immutable one. At the moment, I'm using

guard var (t, u) = myFunction() else { ... }

and letting u be unnecessarily mutable, which would be fine except the compiler issues a warning saying Variable 'u' was never mutated; consider changing to 'let' constant. Obviously if I change the var to a let, the usage of t will break.

Is there a way to unwrap these two variables in one line without any compiler warnings or errors? I've tried guard let (var t, u), guard (var t, let u), but they don't seem to be supported.

2 Likes

In your case, you could do two destructurings on the same line:

guard var (t, _) = tu, let (_, u) = tu else { return }
2 Likes

If I want to avoid double-calling the function, I would need

guard let tu = myFunction(), var (t, _) = tu, let (_, u) = tu else { ... }

which the compiler doesn't like because tu is no longer an optional

I did end up finding a solution though, pattern matching allows the split var/let so you can do

guard case .some(var t, let u) = myFunction() else { ... }
11 Likes

Very nice case trick, I'll save that in my toolbox.

The answer @TellowKrinkle provided:

guard case .some(var t, let u) = myFunction() else { ... }

Can also be written with this syntactic sugar:

guard case (var t, let u)? = myFunction() else { ... }

Reference: Optional Pattern

6 Likes