1. ホーム
  2. casting

[解決済み] 数値型を安全かつイディオムに変換するには?

2022-11-03 01:43:02

質問

編集者注:この質問はRust 1.0より前のバージョンのもので、Rust 1.0に存在しないいくつかの項目を参照しています。回答はまだ貴重な情報を含んでいます。

から変換する慣用的な方法は何ですか? usize から u32 ?

例えば 4294967295us as u32 が動作し 型のキャストに関する Rust 0.12 のリファレンスドキュメント と言っています。

数値は任意の数値型にキャストすることができます。生のポインタ値は、任意の整数型または生のポインタ型に、または、任意の整数型からキャストできます。それ以外のキャストはサポートされていないため、コンパイルに失敗します。

しかし 4294967296us as u32 は黙ってオーバーフローし、0という結果を出します。

私が見つけたのは ToPrimitive FromPrimitive のような素敵な機能を提供する to_u32() -> Option<u32> のような素晴らしい機能を提供しますが、これらは不安定であるとマークされています。

#[unstable(feature = "core", reason = "trait is likely to be removed")]

数値型(およびポインタ型)間の変換を行うための慣用的な(そして安全な)方法は何でしょうか?

プラットフォーム依存のサイズである isize / usize は、私がこの質問をする理由の一つです。元のシナリオは、私が u32 から usize でツリーを表現することができたので Vec<u32> (例えば let t = Vec![0u32, 0u32, 1u32] とすると、ノード 2 の祖父母を得るには t[t[2us] as usize] となる)のですが、もし usize が32ビット未満だった場合、どのように失敗するのだろうと思いました。

どのように解決するのですか?

値の変換

別の型に完全に収まるものから

ここは問題ありません。使用するのは From を使用して、損失が発生していないことを明示します。

fn example(v: i8) -> i32 {
    i32::from(v) // or v.into()
}

を選択することができます。 as を使うこともできますが、必要ないときは避けることが推奨されます(下記参照)。

fn example(v: i8) -> i32 {
    v as i32
}

他のタイプに完全に適合しないタイプから

一般的な意味を持つ単一の方法はありません。あなたは、1つのスペースに2つのものを収める方法を求めているのです。最初の良い試みの1つは Option - Some に収まるときと None である。そして、必要に応じて、プログラムを失敗させたり、デフォルトの値で代用したりすることができます。

Rust 1.34以降では、以下のように TryFrom :

use std::convert::TryFrom;

fn example(v: i32) -> Option<i8> {
    i8::try_from(v).ok()
}

それ以前は、自分で似たようなコードを書くしかない。

fn example(v: i32) -> Option<i8> {
    if v > std::i8::MAX as i32 {
        None
    } else {
        Some(v as i8)
    }
}

別のタイプに完全に収まるかどうかわからないものから

数値の範囲 isize / usize を表すことができます。 はプラットフォームに応じて変化します。 を表すことができます。を使う必要があります。 TryFrom に関係なく 現在 プラットフォームに関係なく

こちらもご覧ください。

as が行う

<ブロッククオート

しかし 4294967296us as u32 は黙ってオーバーフローし、0という結果を出します。

より小さな文字に変換する場合。 as は数値の下位ビットを取り、符号を含む上位ビットは無視します。

fn main() {
    let a: u16 = 0x1234;
    let b: u8 = a as u8;
    println!("0x{:04x}, 0x{:02x}", a, b); // 0x1234, 0x34

    let a: i16 = -257;
    let b: u8 = a as u8;
    println!("0x{:02x}, 0x{:02x}", a, b); // 0xfeff, 0xff
}

も参照してください。

について ToPrimitive / FromPrimitive

RFC 369, Num Reform の記載内容 :

理想的には [...]... ToPrimitive [はすべて削除され、C のような列挙型を扱うより原則的な方法が採用されるでしょう。

その一方で、これらの特性は num crate :