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

Rust中判断一个range是否包含另一个range的惯用方法

Rust中判断一个range是否包含另一个range的惯用方法

我太懂这种别扭感了——你写的第一个测试用例完全符合直觉,但编译器就是不买账,因为contains方法本来就只接受单个元素,不是另一个Range。而你现在用的手动判断方法,那个-1不仅看着不优雅,还容易因为搞混Range的开闭规则出错。

先给你理清核心逻辑:Rust里的Range默认是左闭右开(start ≤ x < end),比如0..42包含0到41,但不包含42;而RangeInclusive(..=)是全闭区间,比如0..=42包含42本身。所以判断一个Range包含另一个Range的关键,是根据区间的开闭类型,比较两者的起始和结束边界。

针对普通左闭右开Range的简洁写法

如果只是处理a..b这种左闭右开的Range,其实完全不需要那个-1,直接比较边界就够了:

#[test]
fn test_rangyness() {
    let a = 0..42;
    let b = 1..41;
    // 核心逻辑:a的起始 ≤ b的起始,且b的结束 ≤ a的结束
    assert!(a.start <= b.start && b.end <= a.end);
}

这个逻辑的本质是:只要b的所有元素都落在a的区间里,就满足包含关系。因为b是左闭右开,所以b的最大元素是b.end - 1,而a的区间包含到a.end - 1,只要b.end ≤ a.end,那b.end -1肯定小于a.end,自然被a包含。

兼容多种Range类型的通用方法

如果你的代码里还会用到RangeInclusive(全闭区间),可以写一个通用的辅助函数,自动处理不同的边界类型:

use std::ops::{Bound, RangeBounds};

/// 判断外层Range是否包含内层Range
fn range_contains_range<Outer, Inner>(outer: Outer, inner: Inner) -> bool
where
    Outer: RangeBounds<<Inner as RangeBounds>::Item>,
    Inner: RangeBounds<<Outer as RangeBounds>::Item>,
    <Outer as RangeBounds>::Item: PartialOrd,
{
    // 获取外层区间的边界值
    let outer_start = match outer.start_bound() {
        Bound::Included(s) => s,
        Bound::Excluded(s) => s,
        Bound::Unbounded => panic!("暂不支持无界区间"),
    };
    let outer_end = match outer.end_bound() {
        Bound::Included(e) => e,
        Bound::Excluded(e) => e,
        Bound::Unbounded => panic!("暂不支持无界区间"),
    };

    // 获取内层区间的边界值
    let inner_start = match inner.start_bound() {
        Bound::Included(s) => s,
        Bound::Excluded(s) => s,
        Bound::Unbounded => panic!("暂不支持无界区间"),
    };
    let inner_end = match inner.end_bound() {
        Bound::Included(e) => e,
        Bound::Excluded(e) => e,
        Bound::Unbounded => panic!("暂不支持无界区间"),
    };

    // 检查起始边界:内层的起始不能超过外层的起始
    let start_ok = match (outer.start_bound(), inner.start_bound()) {
        (Bound::Included(_), Bound::Included(_)) => inner_start <= outer_start,
        (Bound::Included(_), Bound::Excluded(_)) => inner_start < outer_start,
        (Bound::Excluded(_), Bound::Included(_)) => inner_start <= outer_start,
        (Bound::Excluded(_), Bound::Excluded(_)) => inner_start < outer_start,
        _ => false,
    };

    // 检查结束边界:内层的结束不能超过外层的结束
    let end_ok = match (outer.end_bound(), inner.end_bound()) {
        (Bound::Included(_), Bound::Included(_)) => inner_end <= outer_end,
        (Bound::Included(_), Bound::Excluded(_)) => inner_end <= outer_end,
        (Bound::Excluded(_), Bound::Included(_)) => inner_end < outer_end,
        (Bound::Excluded(_), Bound::Excluded(_)) => inner_end < outer_end,
        _ => false,
    };

    start_ok && end_ok
}

用这个函数就可以轻松处理各种区间组合:

#[test]
fn test_mixed_ranges() {
    // 左闭右开包含左闭右开
    let a = 0..42;
    let b = 1..41;
    assert!(range_contains_range(a, b));

    // 全闭区间包含全闭区间
    let c = 0..=42;
    let d = 1..=41;
    assert!(range_contains_range(c, d));

    // 全闭区间包含左闭右开区间
    let e = 0..=42;
    let f = 1..42;
    assert!(range_contains_range(e, f));
}

这样既符合Rust的惯用风格,又避免了手动处理边界的麻烦,还能兼容不同类型的区间。

备注:内容来源于stack exchange,提问作者Fee

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.15 09:13:07