Как мне конвертировать usize в u32, используя TryFrom? - PullRequest
0 голосов
/ 20 мая 2018

Я хочу преобразовать типизированную переменную usize в типизированную переменную u32 в Rust.Мне известно, что переменная 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);
}

Кодне компилируется, со следующей ошибкой компиляции:

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`

Я понял из ошибки компиляции, что наличие TryFrom<usize> для u32 зависит от наличия From<usize> для u32, что выглядит несколькодля меня странно.

Есть ли другой способ, которым я мог бы использовать TryFrom для преобразования из usize в u32?Если нет, есть ли другой идиоматический способ выполнить это преобразование?

Я знаю, что могу использовать ключевое слово as, но оно не уведомляет меня, если что-то пошло не так с преобразованием.Кроме того, я думаю, что могу написать свою собственную функцию, которая выполняет преобразование, но я был бы удивлен, если бы у Rust не было идиоматического способа сделать это преобразование.В конце концов, usize и u32 - это два основных типа.

1 Ответ

0 голосов
/ 20 мая 2018

Поскольку этот ответ был создан, было решено , чтобы реализация TryFrom<usize> всегда учитывала возможность отказа, независимо от текущей платформы.Оригинальный код теперь успешно компилируется в Rust 1.34.

Оригинальный ответ

наличие TryFrom<usize> для u32 зависит от наличия From<usize> для u32, что мне кажется несколько странным

Это потому, что есть общая реализация TryFrom для всего, что реализует From:

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

Как вы упомянули, поскольку Rust поддерживает платформы, где собственная целая длина составляет 16, 32 или 64биты, имеющие такую ​​реализацию From / Into не будут без потерь на некоторых из этих платформ.

Эта ошибка возникает из-за отсутствия прямой реализации TryFrom / TryInto для этих типов.Это связано с тем, что пользователи этих характеристик предпочитают, чтобы реализации были безошибочными, когда они соответствуют платформе (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)
    }
}

Я был бы удивлен, если бы у Rust не было идиоматического способа сделать это преобразование.В конце концов, usize и u32 - это два основных типа.

Проблема в том, что usize на самом деле не является "базовым" типом, поскольку он меняет размер в зависимости от целевой платформы.Получить правильную, эргономичную и нелегко.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...