user2138149
user2138149

Reputation: 17384

Rust convert Option<T> to Option<U>

How can I convert an Option of one type into an Option of another type in Rust?

I managed to sketch this out in the Rust playground, but this is a lot of boilerplate code to do what seems like a common operation.

In this example, I have a data transfer object which contains an Option::<String>, which I wish to convert to an Option::<Price> type, where Price is some internal struct type.

#[derive(Debug)]
struct DTO {
    pub dto_data: Option::<String>,
}

#[derive(Debug)]
struct Price {
    pub internal_price: i64,
}

#[derive(Debug)]
struct InternalType {
    pub internal_data: Option::<Price>,
}

fn main() {

    let dto = DTO {
        dto_data: Some(String::from("10")),
    };
    
    println!("{:?}", dto);
    
    let mut option_price: Option<Price> = None;
    
    if let Some(price_exists) = dto.dto_data {
        option_price = Some(Price {
            internal_price: price_exists.parse().unwrap()
        });
    }
    
    let internal_type = InternalType {
        internal_data: option_price,
    };

    println!("{:?}", internal_type);
    
}

Actually, I am fairly sure there is a bug in my code, because the Rust playground produces warnings about dead code. Still, the output seems ok.

That point aside, does Rust provide a simpler way to do this? Perhaps with some kind of helper function or trait?


Output:

Compiler:

   Compiling playground v0.0.1 (/playground)
warning: field `internal_price` is never read
 --> src/main.rs:9:9
  |
8 | struct Price {
  |        ----- field in this struct
9 |     pub internal_price: i64,
  |         ^^^^^^^^^^^^^^
  |
  = note: `Price` has a derived impl for the trait `Debug`, but this is intentionally ignored during dead code analysis
  = note: `#[warn(dead_code)]` on by default

warning: field `internal_data` is never read
  --> src/main.rs:14:9
   |
13 | struct InternalType {
   |        ------------ field in this struct
14 |     pub internal_data: Option::<Price>,
   |         ^^^^^^^^^^^^^
   |
   = note: `InternalType` has a derived impl for the trait `Debug`, but this is intentionally ignored during dead code analysis

warning: `playground` (bin "playground") generated 2 warnings
    Finished dev [unoptimized + debuginfo] target(s) in 0.80s
     Running `target/debug/playground`

Standard Output:

DTO { dto_data: Some("10") }
InternalType { internal_data: Some(Price { internal_price: 10 }) }

Upvotes: 0

Views: 943

Answers (1)

Finomnis
Finomnis

Reputation: 22818

You are probably asking for Option::map:

#[derive(Debug)]
struct DTO {
    pub dto_data: Option<String>,
}

#[derive(Debug)]
struct Price {
    pub internal_price: i64,
}

#[derive(Debug)]
struct InternalType {
    pub internal_data: Option<Price>,
}

fn main() {
    let dto = DTO {
        dto_data: Some(String::from("10")),
    };

    println!("{:?}", dto);

    let internal_type = InternalType {
        internal_data: dto.dto_data.map(|p| Price {
            internal_price: p.parse().unwrap(),
        }),
    };

    println!("{:?}", internal_type);
}
DTO { dto_data: Some("10") }
InternalType { internal_data: Some(Price { internal_price: 10 }) }

Upvotes: 4

Related Questions