You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于uom crate的Quantity类型别名实现单泛型参数包装

问题:用单个泛型参数包装uom的Quantity类型别名

我使用的crate定义了基础类型Quantity<D,U,V>及多个类型别名,例如:

type Length = Quantity<Dim::L, Meter, f64>;

我希望定义泛型函数或结构体来包装Quantity,但仅接受这些类型别名作为单个泛型参数,而非重复指定D、U、V三个参数。期望实现的结构与函数如下:

struct ParsedQuantity<Q> {
    quantity: Q,
    additional_field: Something
}

fn parse_value<Q>(s: &str) -> Result<ParsedQuantity<Q>, &str>;

其中Q代表上述类型别名,以便能这样使用:

struct Model {
    mass: ParsedQuantity<Mass>
}
let mass = parse_value::<Mass>("1 kg");

如果直接返回Quantity,借助Rust类型推断,即使函数签名为parse_value<D, U, V>也能正常工作:

pub fn parse_value<D, U, V>(s: &str) -> Result<Quantity<D, U, V>, &str>
where
    D: Dimension + ?Sized,
    U: uom::si::Units<V> + ?Sized,
    V: uom::Conversion<V> + uom::num_traits::Num,
    Quantity<D, U, V>: FromStr,
{ /* ... */ }

let parsed: Length = parse_value("1 m").unwrap();

这里D、U、V能被正确推断,但返回包装结构体ParsedQuantity时,类型无法便捷推断,必须手动指定三个类型参数,这不是我想要的结果。

请问该如何操作,才能让函数或结构体接受Q = Quantity<D,U,V>这类别名作为单个泛型参数,而非三个参数?


解决方案

可以通过定义关联Quantity内部参数的trait,将三个参数的约束转移到单个泛型参数上,实现需求。

1. 定义标记trait并自动实现

先定义一个trait,为所有合法的Quantity类型关联出内部的D、U、V参数,并自动为所有Quantity实例实现该trait:

use uom::{Dimension, Conversion};

trait IsQuantity {
    type Dim: Dimension + ?Sized;
    type Units: uom::si::Units<Self::Value> + ?Sized;
    type Value: Conversion<Self::Value> + uom::num_traits::Num;
}

// 为所有Quantity<D,U,V>自动实现IsQuantity
impl<D, U, V> IsQuantity for Quantity<D, U, V>
where
    D: Dimension + ?Sized,
    U: uom::si::Units<V> + ?Sized,
    V: Conversion<V> + uom::num_traits::Num,
{
    type Dim = D;
    type Units = U;
    type Value = V;
}

2. 用trait约束泛型参数

现在可以在结构体和函数中使用单个泛型参数Q,通过IsQuantity trait确保它是合法的Quantity类型:

// 示例包装结构体
struct ParsedQuantity<Q> {
    quantity: Q,
    additional_field: String,
}

// 单个泛型参数的解析函数
fn parse_value<Q>(s: &str) -> Result<ParsedQuantity<Q>, &str>
where
    Q: IsQuantity + std::str::FromStr<Err = &'static str>,
{
    let quantity = s.parse()?;
    Ok(ParsedQuantity {
        quantity,
        additional_field: "解析成功".to_string(),
    })
}

3. 使用示例

直接用类型别名作为泛型参数即可,无需手动指定三个内部参数:

// 假设已定义的类型别名
type Mass = Quantity<Dim::Mass, Kilogram, f64>;

struct Model {
    mass: ParsedQuantity<Mass>,
}

fn main() {
    // 显式指定泛型参数
    let mass = parse_value::<Mass>("1 kg").unwrap();
    println!("解析后的质量: {:?}", mass.quantity);

    // 或通过返回值类型自动推断
    let inferred_mass: ParsedQuantity<Mass> = parse_value("2 kg").unwrap();
}

内容的提问来源于stack exchange,提问作者Lyss

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 02:05:11