Rust and serde deserializing using generics

前端 未结 2 1231
面向向阳花
面向向阳花 2021-01-21 07:47

I am trying to use generics to deserialize structs from file for use with a Swagger generated API. So I have hacked together this which almost works, but I am unable to unpack t

2条回答
  •  星月不相逢
    2021-01-21 08:21

    When you use a type parameter like T here:

    fn readfile(filename: String) -> Result, Box>;
    

    The concrete type of T is determined by the caller. The compiler doesn't just look at all available type and make a guess at what makes sense.

    First of all, you need to tell the compiler that any T passed here will actually work. That means constraining T to be something that is deserializable, within compatible lifetimes:

    // filename should be &str here
    fn readfile<'a, T: ?Sized>(filename: &str) -> Result>, Box>
    where
        for<'de> T: Deserialize<'de> + 'a
    {
        let f = std::fs::File::open(filename)?;
        let config_data: Outer = serde_yaml::from_reader(f)?;
        Ok(Box::new(config_data))
    }
    
    // filename should be &str here
    fn readconfig<'a, T: ?Sized>(filename: &str) -> Result>, &'static str>
    where
        for<'de> T: Deserialize<'de> + 'a
    {
        // read the config file
        let config_data = readfile(filename);
        match config_data {
            Ok(e) => {
                Ok(Box::new(*e)) // need to deref the Box before reboxing
            },
            Err(_) => {
                Err("nadda")
            }
        }
    }
    

    Next, when you call this, you need to tell it a concrete type:

    let result: Box> = readconfig("config.yaml")?;
    

    This will fail if the input cannot be parsed into a Box>, in which case you can try parsing it to Box>, perhaps using Result::or_else.

提交回复
热议问题