Angel Judath Alvarez
Angel Judath Alvarez

Reputation: 349

How to send 'Some' with argument in a function

I am trying to send the result of a match to a function Foo, but the result of the match is type Some()

How can I send it as an argument to the Foo function?

struct Person {
    name: Option<String>,
    lastname: Option<String>,
}

fn Foo(x: Option<String>) {
    println!("{:?}", x);
}

fn main() {
    let name = "Steve".to_string();
    let lastname = "Alvarez".to_string();
    let mut x: Option<Person> = Some(Person {
        name: Some(name),
        lastname: Some(lastname),
    });

    match x {
        Some(Person {
            name: ref a @ Some(_),
            lastname: ref b @ _,
        }) => Foo(a),
        _ => {}
    }
}

Upvotes: 0

Views: 225

Answers (2)

Michael Anderson
Michael Anderson

Reputation: 73570

I think the problem with the existing code is that Foo consumes an Option, while your match gets a reference to an Option. They need to match. There's a few approaches that will work here.

  1. Make Foo and the match both use values. This means you remove the ref on the match pieces. You wont be able to use the Person value after the match, since it will have been chopped into its component pieces.
fn Foo(x: Option<String>) {
    println!("{:?}", x);
}

// ... 

    match x {
        Some(Person {
            name: a @ Some(_),
            lastname: b @ _,
        }) => Foo(a),
        _ => {}
    }

  1. Make Foo and the match both use references. You keep the ref on the match, but add an & to Foo's argument.
fn Foo(x: &Option<String>) {
    println!("{:?}", x);
}

// ... 

    match x {
        Some(Person {
            name: ref a @ Some(_),
            lastname: ref b @ _,
        }) => Foo(a),
        _ => {}
    }

  1. Clone a before passing it to Foo. Foo and the match pattern don't change, but the way you call Foo changes slightly
fn Foo(x: Option<String>) {
    println!("{:?}", x);
}

// ... 

    match x {
        Some(Person {
            name: ref a @ Some(_),
            lastname: ref b @ _,
        }) => Foo(a.clone()),
        _ => {}
    }

Of course, in your particular case you dont need to use pattern matching at all, you could just use some of the tools that already exist in Option, such as map.

x.map(|p| Foo(p.name));

Upvotes: 0

Unapiedra
Unapiedra

Reputation: 16217

Step 1

First, your match x { Some(Person{...})... looks wrong. Unwrap it as Some(person) => foo(person.name).

struct Person {
    name: Option<String>,
    lastname: Option<String>,
}

fn foo(x: Option<String>) {
    println!("{:?}", x);
}

fn main() {
    let name = "Steve".to_string();
    let lastname = "Alvarez".to_string();
    let x: Option<Person> = Some(Person {
        name: Some(name),
        lastname: Some(lastname),
    });

    match x {
        Some(person) => foo(person.name),
        _ => {}
    }
}

Step 2: Make it nicer

Taking an Option as a function argument is not very Rust-like, I believe. (I might be wrong, since I am new to Rust as well.)

Also, the match where the None option is not taken is also an antipattern, I believe. Instead, use a combinator (map or and_then).

struct Person {
    name: Option<String>,
    lastname: Option<String>,
}

fn foo(x: String) {
    println!("{:}", x);
}

fn main() {
    let name = "Steve".to_string();
    let lastname = "Alvarez".to_string();
    let x: Option<Person> = Some(Person {
        name: Some(name),
        lastname: Some(lastname),
    });

    x.and_then(|person| person.name) // person.name is an Option -> thus use `and_then`
        .map(|n| foo(n));
}

Live Playground

Upvotes: 2

Related Questions