Validating multiple Options at once


This might be a really dumb question, but I can’t figure out a nice way to do it.

I have a function which accepts (let’s say) three Option arguments, and I want to perform a validation step where I check that all are Some, then do something with those values if they are.

The naive approach below doesn’t work because Option isn’t copyable. I could provide a default value for each (maybe the empty string) and unwrap them initially, or do it one by one, but I don’t know what the idiomatic way to do this for several at the same time is. Is this even a good idea in Rust?

fn f(a: Option<String>, b: Option<String>, c: Option<String>) -> Option<String> {
    if a.or(b).or(c).is_none() {
        println!("a, b, and c are all required");
        return None;

    let a1 = a.unwrap();
    let b1 = b.unwrap();
    let c1 = c.unwrap();

    Some(format!("{}:{}:{}", a1, b1, c1))


A nice way to do it is to put them all in a 3-element tuple, then pattern-match them back out again:

if let (Some(a), Some(b), Some(c)) = (a, b, c) {
    println!("You passed in {:?}, {:?}, and {:?}");
else {
    println!("Need to pass in all three arguments");


Thanks, that looks nice. I tried adding that, but I can’t get it to work (still complains about using a moved value when I try to unwrap). If I provide different names on the LHS, I don’t seem to get the variables assigned at all.

Is there somewhere I can read up on how that pattern-matching in an assignment should work?


Is there a reason why you can’t do:

if a.is_some()
   && b.is_some()
   && c.is_some() {
else { … }

Regarding @ogham 's solution, in case you need a, b and c after the if let block, you can it adapt to:

if let (&Some(a), &Some(b), &Some(c)) = (&a.as_ref(), &b.as_ref(), &c.as_ref()) {

As for.or(), I think you mistook it for the boolean or || (from the code you wrote), which it is not. You can check out it’s documentation.


Thanks! The only reason I didn’t try that was - I think - I’d assumed that any method on the option was causing the error, not just the or. (I was also wrong about what or does, so thanks for pointing that out too!)


If they are required to be Some why do you not just not use Option and require the callee to unwrap?

fn f(a: String, b: String, c: String) -> Option<String> {
    Some(format!("{}:{}:{}", a, b, c))

fn main() {
    let together = f(Some("a".into()).unwrap(), Some("b".into()).unwrap(), Some("c".into()).unwrap());
    println!("{:?}", together);



You don’t need to unwrap within that if let block. a, b, c will extracted from their Option wrappers, so you can use them as bare values.


Indeed, it’s way nicer to not unwrap at all, so you have the compiler guarantee that you did the check properly!


Thanks guys, those last two really helped clarify for me what makes sense here.