Danilo Bargen
Danilo Bargen

Reputation: 19442

Parse a string to different types

I have a list of sensor specifications. Each sensor type has an accompanying struct. A sensor spec has a sensor type and a key with which the data can be fetched from the database as a string.

Depending on the sensor type, the data should be converted into a numeric value, could be something like u8 or f64.

Here's an example:

use std::collections::HashMap;

struct SensorSpec {
    sensor_type: SensorType,
    data_key: String,
}

enum SensorType {
    A,
    B,
}

#[derive(Debug)]
struct SensorA {
    value: u8,
}

#[derive(Debug)]
struct SensorB {
    value: f64,
}

fn main() {

    // This simulates the database
    let mut db: HashMap<String, String> = HashMap::new();
    db.insert("a".to_string(), "42".to_string());
    db.insert("b".to_string(), "13.37".to_string());

    // List of sensors
    let mut sensor_specs: Vec<SensorSpec> = vec![
        SensorSpec { sensor_type: SensorType::A, data_key: "a".to_string() },
        SensorSpec { sensor_type: SensorType::B, data_key: "b".to_string() },
    ];

    for sensor in sensor_specs {
        // 1. Fetch data as string from db
        // 2. Convert it according to the sensor type
        // 3. Print sensor object to terminal

        let val = db.get(&sensor.data_key);

        let s = match sensor.sensor_type {
            SensorType::A => {
                SensorA { value: val }
            },
            SensorType::B => {
                SensorB { value: val }
            },
        };

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

}

There are two problems with this:

  1. I need to convert the string to a numeric type depending on the sensor type. How do I do that?
  2. Match arm have incompatible types.

Here's the compile message for #2:

example.rs:43:17: 50:10 error: match arms have incompatible types: 
expected `SensorA`,
    found `SensorB`

How can I solve this issue?

Upvotes: 0

Views: 644

Answers (1)

isekaijin
isekaijin

Reputation: 19742

I'd replace your SensorType enum with the following one:

enum Sensor {
    A(SensorA),
    B(SensorB)
}

This has the advantage that you can put both classes of Sensor in the same container:

let sensorA = ...;
let sensorB = ...;
let mut vec = vec!( Sensor::A( sensorA ), Sensor::B( sensorB ) );

Or write your own functions that expect either class of Sensor:

fn use_sensor( sensor: &Sensor ) {
    match sensor {
        Sensor::A( sensorA ) => sensorA.foo(),
        Sensor::B( sensorB ) => sensorB.bar()
    }
}

Upvotes: 1

Related Questions