Abstracting field access

Ok, guys, I've got a good one for you here (I think).

I've got these structs:

#[derive(Serialize, Deserialize, Debug, Eq, Hash, PartialEq, Clone)]
pub struct PositionKey {
    pub symbol: String,
    pub group: String,
    pub fund: String,
    pub broker: String,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Position {
    pub key: PositionKey,
    pub country: String,
    pub qty: f64,
}

and this fn:

fn mvBySymbol(positions: Vec<Position>, prices: HashMap<String, f64>) -> Vec<f64> {
    let mut result = Vec::new();
    for position in positions {
        let price = *prices.get(&position.key.symbol).unwrap();
        result.push(calcMV(position, price));
    }
    result
}

What I'd like to do is generalize this function so I can calc MV by symbol, group, fund, or broker - any of the PositionKey fields.

So rather than the fn accessing position.key.symbol (or whatever) directly, it'll be passed a lambda of some sort that will extract the field.

What the best/most performant/most idiomatic way to do this in Rust?

The closure approach would be fine.

I suggest changing your method signatures so you don't have to clone Vecs HashMaps and Positions all the time; that's surely going to dwarf any performance considerations of a thin, probably-inlined closure.

fn calcMV(_position: &Position, price: f64) -> f64 {
    price
}

fn mvBySymbol<F>(positions: &[Position], prices: &HashMap<String, f64>, mut accessor: F) -> Vec<f64>
where
    F: FnMut(&Position) -> &str,
{
    let mut result = Vec::new();
    for position in positions {
        let key = accessor(position);
        let price = *prices.get(key).unwrap();
        result.push(calcMV(position, price));
    }
    result
}

...and also your function names to be snake_case so they are idiomatic, like the warnings say.

1 Like