如何使用TryFrom将usize转换为u32?

rea*_*eal 6 rust

我想将一个usize类型变量转换为u32Rust中的类型变量.我知道usize变量可能包含一个大于2 ^ 32的值,在这种情况下转换应该失败.我正在尝试使用TryFrom特征来执行转换.

这是一个简单的例子(Nightly Rust,Playground):

#![feature(try_from)]
use std::convert::TryFrom;

fn main() {
    let a: usize = 0x100;
    let res = u32::try_from(a);
    println!("res = {:?}", res);
}
Run Code Online (Sandbox Code Playgroud)

代码无法编译,出现以下编译错误:

error[E0277]: the trait bound `u32: std::convert::From<usize>` is not satisfied
 --> src/main.rs:6:15
  |
6 |     let res = u32::try_from(a);
  |               ^^^^^^^^^^^^^ the trait `std::convert::From<usize>` is not implemented for `u32`
  |
  = help: the following implementations were found:
            <u32 as std::convert::From<std::net::Ipv4Addr>>
            <u32 as std::convert::From<u8>>
            <u32 as std::convert::From<char>>
            <u32 as std::convert::From<u16>>
  = note: required because of the requirements on the impl of `std::convert::TryFrom<usize>` for `u32`
Run Code Online (Sandbox Code Playgroud)

我从编译错误中推断出拥有TryFrom<usize>for u32依赖于From<usize>for u32,这对我来说似乎有点奇怪.

有没有其他方法我可以利用TryFrom转换usizeu32?如果没有,是否还有其他惯用方法来执行此转换?

我知道我可以使用as关键字,但如果转换出现问题,它不会通知我.另外,我认为我可以编写自己的函数进行转换,但是如果Rust没有一些惯用的方法来进行转换,我会感到惊讶.usizeu32有两种基本类型,毕竟.

She*_*ter 8

由于创建了这个答案,因此TryFrom<usize>无论当前平台如何,都决定实施始终允许失败的可能性.原始代码现在可以在每晚Rust中成功编译.

原始答案

TryFrom<usize>u32依赖于具有From<usize>u32,这似乎有些奇怪,我

这是因为对于实现的TryFrom任何事情都有一个全面的实现From:

impl<T, U> TryFrom<U> for T
where
    T: From<U>,
{
    type Error = !;
}
Run Code Online (Sandbox Code Playgroud)

正如您所提到的,由于Rust支持本机整数长度为16位,32位或64位的平台,因此在某些平台上实现这样的From/ Into不会是无损的.

发生此错误是因为没有针对这些类型的TryFrom/ 的直接实现TryInto.这是因为这些特征的用户更喜欢在适合平台(The type Error = !)时实现是绝对可靠的.

有一个单独的跟踪问题49415专门用于决定此问题.

我认为我可以编写自己的函数进行转换

是的,这就是你应该做的.像这段未经测试的代码:

use std::u32;

struct SomeError;

// usize is a u16 or u32, which always fits in a u32
#[cfg(any(target_pointer_width = "16", target_pointer_width = "32"))]
fn my_thing(a: usize) -> Result<u32, SomeError> {
    Ok(a as u32)
}

// usize is a u64, which might be too big
#[cfg(target_pointer_width = "64")]
fn my_thing(a: usize) -> Result<u32, SomeError> {
    if a > u32::MAX as usize {
        Err(SomeError)
    } else {
        Ok(a as u32)
    }
}
Run Code Online (Sandbox Code Playgroud)

如果Rust没有一些惯用的方法来进行这种转换,我会感到惊讶.usizeu32有两种基本类型,毕竟.

问题是它usize不是真正的"基本"类型,因为它根据目标平台改变大小.要获得正确,高效符合人体工程学的这一点并非易事.