我们应该在 Rust 中使用 Solidity 风格的溢出检查(a * b / b == a),还是像 checked_mul() 这样的原生检查操作?

Should we use Solidity style overflow checks ( a * b / b == a) in Rust, or native checked operations like checked_mul()?

Solidity 没有本机溢出检查。我们可以通过检查是否 a * b / b == a.

来实现 a * b 的自定义乘法检查
uint256 product = a * b;
if (product / b == a) {
    // No overflow
} else {
    // Handle overflow
}

solidity 风格与 idomatic rust 风格的权衡是什么 (checked_mul())?这是一个智能合约,所以我想优化性能。由于溢出检查,Solidity 样式在调试模式下会出现 panic,因此我不得不在发布时进行测试。

团结风格

let product = a * b;
if product / b == a {
    // No overflow
} else {
    // Handle overflow
}

Rust 惯用风格

match a.checked_mul(b) {
    Some(product) => todo!("No overflow"),
    None => todo!("Handle overflow"),
}

我会说为此使用惯用的方法。仅仅是因为人体工程学,并且已经在检查的操作中进行了实施。关于性能,我会说要信任编译器,如果您仍然不确定,则对其进行基准测试。

首先,始终假设标准库具有可能的最佳实现,除非基准测试显示并非如此。在这种情况下,checked_mul() 方法是 implemented via an intrinsic, and you'll hardly get something better. You can see that it compiles down to a simple check of the overflow flag on x86, for example: https://rust.godbolt.org/z/rGrdfab7a.

此外,如果 a 为零怎么办?这会 panic,即使这种情况对你无效,编译器仍然被迫处理它:https://rust.godbolt.org/z/Gnax6z5x9.

即使你帮助优化器,似乎 LLVM 也无法优化这个模式:https://rust.godbolt.org/z/4xq97WxcT.

因此,只需使用 checked_mul()