【问题标题】:How do I convert between numeric types safely and idiomatically?如何安全且惯用地在数字类型之间进行转换?
【发布时间】:2015-04-01 03:06:10
【问题描述】:

编者注:这个问题来自 Rust 1.0 之前的版本,并引用了 Rust 1.0 中不存在的一些项目。答案仍然包含有价值的信息。

从(比如)usize 转换为u32 的惯用方式是什么?

例如,使用4294967295us as u32 进行强制转换有效,而Rust 0.12 reference docs on type casting 则说

数值可以转换为任何数值类型。原始指针值可以转换为或从任何整数类型或原始指针类型转换。不支持任何其他类型转换,并且将无法编译。

4294967296us as u32 会静默溢出并给出结果 0。

我发现ToPrimitiveFromPrimitive 提供了像to_u32() -> Option<u32> 这样的好功能,但它们被标记为不稳定:

#[unstable(feature = "core", reason = "trait is likely to be removed")]

在数字(和指针)类型之间转换的惯用(和安全)方法是什么?

isize / usize 的平台依赖大小是我问这个问题的一个原因 - 最初的场景是我想从 u32 转换为 usize 所以我可以代表一棵树一个Vec<u32>(例如let t = Vec![0u32, 0u32, 1u32],那么要获得节点2的祖父母将是t[t[2us] as usize]),我想知道如果usize小于32位,它将如何失败。

【问题讨论】:

  • 小心使用isize / usize - 它们可以代表您正在编译的changes based on the platform 的数字范围!改用u64 可能会更好地表达您的示例。

标签: casting rust numbers


【解决方案1】:

转换值

从一个完全适合另一个的类型

这里没有问题。使用From trait 明确表示没有损失发生:

fn example(v: i8) -> i32 {
    i32::from(v) // or v.into()
}

您可以选择使用as,但建议在不需要时避免使用它(见下文):

fn example(v: i8) -> i32 {
    v as i32
}

来自不完全适合另一个类型的类型

没有一种方法具有普遍意义——您要问的是如何在一个空间中放置两件东西。一个好的初始尝试是在值合适时使用OptionSome,否则使用None。然后,您可以使程序失败或替换默认值,具体取决于您的需要。

从 Rust 1.34 开始,您可以使用TryFrom

use std::convert::TryFrom;

fn example(v: i32) -> Option<i8> {
    i8::try_from(v).ok()
}

在此之前,您必须自己编写类似的代码:

fn example(v: i32) -> Option<i8> {
    if v > std::i8::MAX as i32 {
        None
    } else {
        Some(v as i8)
    }
}

as 做了什么

4294967296us as u32 会静默溢出并给出结果 0

当转换为更小的类型时,as 只取数字的低位,忽略高位,包括符号:

fn main() {
    let a: u16 = 0x1234;
    let b: u8 = a as u8;
    println!("0x{:04x}, 0x{:02x}", a, b); // 0x1234, 0x34

    let a: i16 = -257;
    let b: u8 = a as u8;
    println!("0x{:02x}, 0x{:02x}", a, b); // 0xfeff, 0xff
}

另见:

关于ToPrimitive / FromPrimitive

RFC 369, Num Reform, states:

理想情况下 [...] ToPrimitive [...] 将全部被删除,以支持使用类似 C 的枚举的更有原则的方式

与此同时,这些特征仍然存在于num crate

【讨论】:

  • 关于如何将 2 个东西放入一个意味着 1: 的空间中,因此返回 Option&lt;u32&gt; 的 API 似乎正是我想要的 - ToPrimitive 没有替代品吗?这就是我所期待的答案类型(尽管您的 sn-p 也很有用)。
  • @Caspar 我不能直接替换,但确实修改了我的答案以包含更多关于做什么的指示。
  • @Caspar 我需要同样的东西并打包到自己的箱子中:crates.io/crates/as_num
  • 我以为as 在调试模式下会出现恐慌,而在发布模式下只会默默溢出?
  • @HutchMoore as 永远不会恐慌,AFAIK。只有数学运算(例如加法,减法)恐慌。虽然通常被认为是调试/发布,但它是单独可控的。见How to compile and run an optimized Rust program with overflow checking enabled
猜你喜欢
  • 1970-01-01
  • 2017-09-28
  • 1970-01-01
  • 2021-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-20
  • 1970-01-01
相关资源
最近更新 更多