【问题标题】:How to add or multiply two i16 in Rust to form an i32 without overflowing?如何在 Rust 中将两个 i16 相加或相乘以形成一个 i32 而不会溢出?
【发布时间】:2019-07-21 10:45:49
【问题描述】:

如何将 Rust 中的两个 i16 数字相加或相乘成更大的 i32 而不会溢出?

let a: i16 = i16::max_value();
let b: i16 = i16::max_value();
let c: i32 = a + b; // throws EO308 "Expected `u32`, found `u16`

【问题讨论】:

    标签: rust integer-overflow


    【解决方案1】:

    Rust 中没有整体提升或隐式强制转换,因此您必须手动进行所有类型转换。

    对于演员表,您可以使用<value> as <type>。但是,如果目标类型是原始类型的超集并且转换它不会丢失信息(例如您的案例),您可以使用 <type>::from 自行记录它:

    let a: i16 = i16::max_value();
    let b: i16 = i16::max_value();
    let c: i32 = i32::from(a) + i32::from(b);
    assert_eq!(c, 65534);
    

    这种特殊情况不会溢出,但对于其他情况,您可以使用{integer}::checked_*() 函数防止溢出:

    let a: i16 = i16::max_value();
    let b: i16 = i16::max_value();
    let c: Option<i16> = a.checked_add(b);
    assert_eq!(c, None); //overflow!
    

    请注意,在调试版本中,整数操作溢出默认情况下会出现恐慌。

    如果您想要的是包装算术,就像在旧 C 中一样,您可以使用 {integer}::wraping_*(),另外它还适用于有符号和无符号值。

    let a: i16 = i16::max_value();
    let b: i16 = i16::max_value();
    let c: i16 = a.wrapping_add(b);
    assert_eq!(c, -2);
    

    【讨论】:

    • @PetrusTheron:不是真的,它会生成完全相同的代码。这个想法是 Rust 严重依赖于类型推断,所以如果将来你的类型发生变化导致转换可能溢出,那么这段代码将无法编译。
    • 请注意,典型整数加法中的溢出只会在调试模式下编译时出现恐慌。
    • “如果你想要的是包装算术,就像在旧 C 中一样”:note that this is considered undefined behavior.
    • @E_net4:不完全是。 Rust 语言 指定溢出的结果是未指定的,并且可能是恐慌。 rustc 编译器 允许使用开关选择两种行为之一:恐慌或包装;此外,它还默认在 Debug 中恐慌并在 Release 中包装,但用户始终可以更改它。理想情况下,rustc 在默认情况下希望总是恐慌,但是 LLVM 对此类代码的优化很差,而且恐慌的存在通常会阻碍矢量化,因此 Release 的默认值必须包装以匹配 C 性能暂时
    • @lights0123:这仅适用于签名溢出。在 C 中,无符号溢出是明确定义的。我在回答中暗示了这一点,但我不想深入这些细节,因为这不是关于 C 而是关于 Rust 的问题。
    【解决方案2】:

    您可以在添加之前将它们都转换为i32

    let c: i32 = (a as i32) + (b as i32); 
    

    【讨论】:

    • 现在使用 FromTryFrom 会更习惯用语。
    • @mcarton:很高兴知道,谢谢。我什至不是生锈的新手。只是一个胚胎:)
    • @SergioTulentsev: as 工作正常,只是不便于维护。如果a 的类型切换到i64 操作a as i32 将继续编译,现在默默地截断值。 From 仅定义为不会失败的转换,因此会停止编译。 TryFrom 是为所有转换定义的,但会返回一个 Option&lt;Target&gt;,它必须在运行时解包;它通常用于可能失败的转换。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-23
    相关资源
    最近更新 更多