为什么Rust中的usize向u128转换被认为是可能失败的?

5

看一下:

use std::convert::{From, TryFrom};

fn main() {
  let size: usize = 42;
  let good: u128  = u128::try_from(size).unwrap(); // works fine
  let bad:  u128  = u128::from(size);              // doesn't compile!
}

据我所知,usize是一种整数类型,这些类型的位数永远不会大于128位。因此,我认为usize -> u128转换不可能失败。那么,为什么u128没有实现From<usize>呢?
更新:Rust的文档中说:

从T到U意味着从U到T的Into

尽管usize -> u128看起来没问题,但u128 -> usize不行。好吧,但为什么没有为usize实现Into<u128>呢?

3
usize是指针的大小。理论上,你可能需要一个寻址空间超过128位的系统……也许将来会有这样的系统。这是未雨绸缪的做法,哈哈。 - T.J. Crowder
“从 T 到 U 意味着从 U 到 T” 在这种情况下,它意味着 usize -> u128u128 <- usize 都可以。它并不涉及 u128 -> usize - mcarton
2个回答

5
尽管usize到u128看起来没问题,但是u128到usize就不行了。好的,那为什么没有实现usize而是实现了Into呢?
这是因为尽管在Rust中usize保证至少是16位,但并不保证usize始终小于或等于64位。
虽然256位指针似乎永远都不会有用,但从技术上讲,没有任何限制,而且由于usize保证是指针大小,所以usize到u128的转换可能失败。

1
普遍的做法不是应该在目标平台usize小于等于128位时将其定义为有条件的吗?这样它总是存在并编译,但如果你以后针对具有256位指针的疯狂假设平台,则不会定义它,你的程序也无法编译。 - Eloff
不,使核心stdlib trait“有条件定义”并不是一件正常的事情,至少对于标准库来说是这样。标准库的正常做法是定义特定于平台的扩展trait,这在这里并不相关。 - Masklinn
我的方法似乎比在所有平台上都没有定义特征更好,事实上它目前可以在所有支持的平台上定义。无论是否有先例,这并不是真正重要的。 - Eloff
“更加方便”并不意味着“更好”。而先例实际上是很重要的,核心特性的消失是一项重大的政策变化,而不是一个无害的观点差异。另请参见:#37423,#70460。 - Masklinn

0

Trait文档中提到:

注意:该trait不能失败。如果转换可能失败,请使用TryFrom。

由于您不知道usize是否可以容纳u16/u32/u64/u128值(取决于编译目标),因此所有这些原始类型都实现了TryFrom而不是From。

在Rust文档中,“implies”意味着当您的类型实现了“From”时,编译器会自动为您提供“Into”(请注意,反之则不成立)。相同的想法适用于“TryFrom”和“TryInto”。因此,以下代码将按预期工作。

use std::convert::{TryFrom,TryInto};

fn main() {
  let size: usize = 42;
  let good: u128  = u128::try_from(size).unwrap();
  let doublegood:usize = good.try_into().unwrap();
}

你说得对,但请检查更新的帖子:为什么 usize 没有实现 Into<u128>?我认为这并不意味着 From(这将是不安全的)或其他任何东西。 - passing_through
1
@passing_through 认为这是为了保持一致性,因为在今天的硬件中,从usize到u32、u16和u8的转换不能得到保证。Rust面向未来,我们可能会看到有一天PC上安装了128位或256位的CPU。如果真的到了那一天,从usize到u128的转换也将不安全。因此,如果rust今天实现了一个Into,它必须被改为TryInto,任何依赖于这个功能的程序都将面临崩溃或完全无法工作的风险。此外,我们已经在rust中有一个整洁的as来进行不安全的转换。 - whilrun

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接