【问题标题】:How to idiomatically convert between u32 and usize?如何在 u32 和 usize 之间进行惯用转换?
【发布时间】:2017-09-28 00:31:14
【问题描述】:

此代码有效并打印“b”:

fn main() {
    let s = "abc";
    let ch = s.chars().nth(1).unwrap();
    println!("{}", ch);
}

另一方面,此代码会导致类型不匹配错误。

fn main() {
    let s = "abc";
    let n: u32 = 1;
    let ch = s.chars().nth(n).unwrap();
    println!("{}", ch);
}
error[E0308]: mismatched types
 --> src/main.rs:5:28
  |
5 |     let ch = s.chars().nth(n).unwrap();
  |                            ^ expected usize, found u32

由于某些外部原因,我必须将 u32 类型用于变量 n。如何将u32 转换为usize 并在nth() 中使用?

【问题讨论】:

  • usize 转换为u32 或反之亦然有哪些常见用例?

标签: types rust type-conversion


【解决方案1】:

as 运算符适用于所有数字类型:

let ch = s.chars().nth(n as usize).unwrap();

Rust 强制你转换整数以确保你知道有符号或溢出。

整数常量可以有类型后缀:

let n = 1u32;

但是,请注意负常数,例如 -1i32 在内部是 - 1i32

在没有明确类型说明的情况下声明的整数变量显示为{integer},并且将从方法调用之一正确推断。

【讨论】:

  • 为了保护盲目复制和粘贴此答案的人:我认为@Shepmaster (stackoverflow.com/a/55769098/1290383) 的答案应该是“已接受”的答案。有人可能会在这里偶然发现这个答案,认为使用 as 可以节省数字转换,但事实并非如此。
【解决方案2】:

您可以做的最谨慎的事情是使用TryFrom 并在值无法放入usize 时恐慌:

use std::convert::TryFrom;

fn main() {
    let s = "abc";
    let n: u32 = 1;
    let n_us = usize::try_from(n).unwrap();
    let ch = s.chars().nth(n_us).unwrap();
    println!("{}", ch);
}

盲目地使用as,当你的代码在usize小于32位的平台上运行时,你的代码会以一种神秘的方式失败。例如,一些微控制器使用 16 位整数作为原生大小:

fn main() {
    let n: u32 = 0x1_FF_FF;
    // Pretend that `usize` is 16-bit
    let n_us: u16 = n as u16;
    
    println!("{}, {}", n, n_us); // 131071, 65535
}

对于u32 以外的更广泛的数字转换类型 usize,请参阅How do I convert between numeric types safely and idiomatically?

【讨论】:

  • 我认为在使用TryFrom 之前,对于某些情况,开发人员还可以使用From 特征(例如u32::from(n)。如果演员表不是,这应该会在编译时发出错误在 Rust 编译器中实现。但是:据我所见,isizeusizeFrom 特征仅针对 u8 和 u16 实现,但根据平台不进行检查(参见 doc.rust-lang.org/src/core/convert/num.rs.html#44doc.rust-lang.org/src/core/convert/num.rs.html#135)。这可能是 8 位微控制器的问题(不确定 Rust 是否支持它们)
  • @obraunsdorf 链接到涵盖该问题的现有答案,谢谢。
【解决方案3】:

当我们尝试编译您的代码时,我们现在有一个完全不同的答案,将数字 1 替换为 i32 类型的变量:

error[E0308]: mismatched types
 --> src/main.rs:5:28
  |
5 |     let ch = s.chars().nth(n).unwrap();
  |                            ^ expected usize, found i32
help: you can convert an `i32` to `usize` and panic if the converted value wouldn't fit
  |
5 |     let ch = s.chars().nth(n.try_into().unwrap()).unwrap();
  |    

这意味着现在编译器建议您使用 n.try_into().unwrap(),它利用了 TryInto 特性,而 TryInto 又依赖于 TryFrom 并返回 Result<T, T::Error>。这就是为什么我们需要用.unwrap()提取结果

TryInto documentation

【讨论】:

  • 这实际上已经被existing answer 覆盖,因为TryFrom / TryInto 是彼此的镜像。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-01
  • 2017-03-16
  • 2013-02-15
  • 1970-01-01
  • 2016-03-09
相关资源
最近更新 更多