如何安全地、惯用地在数字类型之间进行转换?
How do I convert between numeric types safely and idiomatically?
Editor's note: This question is from a version of Rust prior to 1.0 and references some items that are not present in Rust 1.0. The answers still contain valuable information.
从(比如)usize
转换为 u32
的惯用方法是什么?
例如,使用 4294967295us as u32
进行转换并且 Rust 0.12 reference docs on type casting 说
A numeric value can be cast to any numeric type. A raw pointer value can be cast to or from any integral type or raw pointer type. Any other cast is unsupported and will fail to compile.
但是4294967296us as u32
会悄无声息地溢出并给出结果0。
我发现 ToPrimitive
and FromPrimitive
提供了很好的功能,例如 to_u32() -> Option<u32>
,但它们被标记为不稳定:
#[unstable(feature = "core", reason = "trait is likely to be removed")]
在数字(和指针)类型之间进行转换的惯用(且安全)方法是什么?
isize
/ usize
的 platform-dependent 大小是我问这个问题的原因之一 - 最初的情况是我想从 u32
转换为usize
所以我可以在 Vec<u32>
中表示一棵树(例如 let t = Vec![0u32, 0u32, 1u32]
,然后得到节点 2 的 grand-parent 将是 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
}
来自不完全适合另一个的类型
没有一种方法具有普遍意义 - 您是在问如何将两个东西放入一个 space 中。一个好的初始尝试是在值适合时使用 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
可以代表您正在编译的 changes based on the platform。无论您的当前平台如何,您都需要使用TryFrom
。
另请参阅:
- Why is type conversion from u64 to usize allowed using `as` but not `From`?
as
的作用
but 4294967296us as u32
will silently overflow and give a result of 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
Ideally [...] ToPrimitive
[...] would all be removed in favor of a more principled way of working with C-like enums
与此同时,这些特征在 num crate 中继续存在:
Editor's note: This question is from a version of Rust prior to 1.0 and references some items that are not present in Rust 1.0. The answers still contain valuable information.
从(比如)usize
转换为 u32
的惯用方法是什么?
例如,使用 4294967295us as u32
进行转换并且 Rust 0.12 reference docs on type casting 说
A numeric value can be cast to any numeric type. A raw pointer value can be cast to or from any integral type or raw pointer type. Any other cast is unsupported and will fail to compile.
但是4294967296us as u32
会悄无声息地溢出并给出结果0。
我发现 ToPrimitive
and FromPrimitive
提供了很好的功能,例如 to_u32() -> Option<u32>
,但它们被标记为不稳定:
#[unstable(feature = "core", reason = "trait is likely to be removed")]
在数字(和指针)类型之间进行转换的惯用(且安全)方法是什么?
isize
/ usize
的 platform-dependent 大小是我问这个问题的原因之一 - 最初的情况是我想从 u32
转换为usize
所以我可以在 Vec<u32>
中表示一棵树(例如 let t = Vec![0u32, 0u32, 1u32]
,然后得到节点 2 的 grand-parent 将是 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
}
来自不完全适合另一个的类型
没有一种方法具有普遍意义 - 您是在问如何将两个东西放入一个 space 中。一个好的初始尝试是在值适合时使用 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
可以代表您正在编译的 changes based on the platform。无论您的当前平台如何,您都需要使用TryFrom
。
另请参阅:
- Why is type conversion from u64 to usize allowed using `as` but not `From`?
as
的作用
but
4294967296us as u32
will silently overflow and give a result of 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
Ideally [...]
ToPrimitive
[...] would all be removed in favor of a more principled way of working with C-like enums
与此同时,这些特征在 num crate 中继续存在: