首页 > 解决方案 > 如何在函数中使用泛型并在 rust 中使用模式匹配?

问题描述

我正在解决一个名为 Syracuse 问题(3n+1​​ 问题)的小数学问题。

事情是我希望我的函数适用于 2 种类型,一种是 u64,另一种是通过包含 2 个我称为 U128 的 u64 来扩展 u64 大小的结构。

我的 u64 函数看起来像这样

fn syracuse(n: u64) -> u64 {
    match n % 2 {
        0 => n / 2,
        1 => 3 * n + 1,
        _ => 1,
    }
}

我已经尝试对我的 U128 和 u64 实现一个特征。

fn syracuse<T>(n: T) -> T where T : Add +Mul+Div+Rem + Basic0123 {
    match n % Basic0123::two() {
        Basic0123::zero() => n / Basic0123::two(),
        Basic0123::one() => Basic0123::three() * n + Basic0123::one(),
        _ => Basic0123::one(),
    }
}

它不编译,模式匹配不喜欢这样。我是 rust 新手,我试图了解创建一个具有通用类型的函数是否可以解决这个仅以 DRY 方式处理 2 种不同类型的问题,或者我应该坚持简单地为 U128 类型重写函数?

标签: functiongenericsrust

解决方案


我只是假设评论中的大部分内容都已处理,并且您将回到使用std::u128原始类型而不是您自己的类型。

在泛型类型上实现 Syracuse 猜想的正确方法如下:

fn syracuse<T>(n: T) -> T
    where T : Copy + Eq + Add<Output = T> + Mul<Output = T> + Div<Output = T> + Rem<Output = T> + From<u32> {

    let zero:T = 0.into();
    match n % 2.into() == zero {
        true => n/(2.into()),
        false => n * (3.into()) + 1.into()
    }
}

按出场顺序:

  • Copy是必需的,因为我们不需要Remon &T,而是 onT
  • 所有Output类型规范都是这样我们不会隐式更改类型 - 操作T将始终映射到T
  • 我们要求Eq,所以我们可以比较余数的结果
  • 我们要求From<u32>,所以我们可以into()每一个数字常数

工作版本可以在这里找到


推荐阅读