如何使用 TryFrom 将 usize 转换为 u32? [英] How do I convert a usize to a u32 using TryFrom?

查看:46
本文介绍了如何使用 TryFrom 将 usize 转换为 u32?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

#![feature(try_from)]使用 std::convert::TryFrom;fn 主(){让一个:usize = 0x100;让 res = u32::try_from(a);println!("res = {:?}", res);}

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

error[E0277]: trait bound `u32: std::convert::From` 不满足-->src/main.rs:6:15|6 |让 res = u32::try_from(a);|^^^^^^^^^^^^^ 特性 `std::convert::From<usize>` 没有为 `u32` 实现|= 帮助:找到以下实现:<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>>= 注意:由于对 `u32` 的 `std::convert::TryFrom<usize>` 的 impl 的要求是必需的

我从编译错误中推断出 TryFrom 用于 u32 依赖于 From 用于 u32,我觉得有点奇怪.

还有其他方法可以利用 TryFromusize 转换为 u32 吗?如果没有,有没有其他惯用的方式来执行这种转换?

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

解决方案

自从创建了这个答案,决定TryFrom 的实现始终允许失败的可能性,无论当前平台如何.原始代码现在可以在 Rust 1.34 中成功编译.

原答案

<块引用>

具有 TryFrom 用于 u32 依赖于 From 用于 u32,其中我觉得有点奇怪

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

implTryFrom对于 T在哪里T:来自<U>,{输入错误 = !;}

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

发生此错误的原因是这些类型没有直接实现 TryFrom/TryInto.这是因为这些特性的用户更喜欢在适合平台的情况下实现无误(type Error = !).

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

<块引用>

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

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

使用 std::u32;结构体错误;//usize 是 u16 或 u32,它们总是适合 u32#[cfg(any(target_pointer_width = "16", target_pointer_width = "32"))]fn my_thing(a: usize) ->结果{好的(a 为 u32)}//usize 是一个 u64,可能太大了#[cfg(target_pointer_width = "64")]fn my_thing(a: usize) ->结果{如果 a >u32::MAX 作为使用 {错误(一些错误)} 别的 {好的(a 为 u32)}}

<块引用>

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

问题在于 usize 并不是真正的基本"类型,因为它会根据目标平台改变大小.获得正确、高性能的符合人体工程学的设计并不容易.

I want to convert a usize typed variable into a u32 typed variable in Rust. I am aware that the usize variable might contain a value larger than 2^32, and in that case the conversion should fail. I am trying to use the TryFrom trait to perform the conversion.

This is a simple example (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);
}

The code doesn't compile, with the following compilation error:

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`

I deduce from the compilation error that having TryFrom<usize> for u32 is dependent on having From<usize> for u32, which seems somewhat strange to me.

Is there any other way I could utilize TryFrom to convert from usize to u32? If not, is there any other idiomatic way to perform this conversion?

I know that I can use the as keyword, but it doesn't notify me if something went wrong with the conversion. In addition, I think that I can write my own function that does the conversion, but I would be surprised if Rust doesn't have some idiomatic way to do this conversion. usize and u32 are two basic types, after all.

解决方案

Since this answer was created, it was decided to have the implementation of TryFrom<usize> always allow for the possibility of failure, regardless of the current platform. The original code now compiles successfully in Rust 1.34.

Original answer

having TryFrom<usize> for u32 is dependent on having From<usize> for u32, which seems somewhat strange to me

This is because there's a blanket implementation of TryFrom for anything that implements From:

impl<T, U> TryFrom<U> for T
where
    T: From<U>,
{
    type Error = !;
}

As you mentioned, since Rust supports platforms where the native integer length is 16, 32, or 64 bits, having such an implementation of From / Into would not be lossless on some of these platforms.

This error occurs because there's no direct implementation of TryFrom / TryInto for these types. This is because users of these traits prefer that the implementations be infallible when platform-appropriate (The type Error = !).

There is a separate tracking issue 49415 specifically for deciding this issue.

I think that I can write my own function that does the conversion

Yes, that is what you should do. Something like this untested piece of code:

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)
    }
}

I would be surprised if Rust doesn't have some idiomatic way to do this conversion. usize and u32 are two basic types, after all.

The problem is that usize isn't really a "basic" type because it changes size depending on the target platform. Getting this correct, performant and ergonomic is not easy.

这篇关于如何使用 TryFrom 将 usize 转换为 u32?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆