有没有一种简单的方法可以一次转换整个标量值元组?
Is there an easy way to cast entire tuples of scalar values at once?
我想将 (u16, u16)
转换为 (f32, f32)
。这是我试过的:
let tuple1 = (5u16, 8u16);
let tuple2 = tuple1 as (f32, f32);
理想情况下,我想避免写作
let tuple2 = (tuple1.0 as f32, tuple1.1 as f32);
没有,
那里
是
没有。
不,你不能。这大致相当于 "can I cast all the fields in a struct to different types all at once?".
你可以写一个通用的扩展特征,它可以为你做这个转换,唯一的问题是我不相信有任何现有的通用"conversion"特征它还定义了 u16 -> f32
实现。
如果您真的想要一个执行此操作的函数,这里有一个您可以构建的尽可能最小的框架:
trait TupleCast<T> {
type Output;
fn tuple_cast(self) -> <Self as TupleCast<T>>::Output;
}
impl<T> TupleCast<T> for () {
type Output = ();
fn tuple_cast(self) -> <() as TupleCast<T>>::Output {
()
}
}
impl<S, T> TupleCast<T> for (S,) where S: CustomAs<T> {
type Output = (T,);
fn tuple_cast(self) -> <(S,) as TupleCast<T>>::Output {
(self.0.custom_as(),)
}
}
impl<S, T> TupleCast<T> for (S, S) where S: CustomAs<T> {
type Output = (T, T);
fn tuple_cast(self) -> <(S, S) as TupleCast<T>>::Output {
(self.0.custom_as(), self.1.custom_as())
}
}
// You would probably have more impls, up to some size limit.
// We can't use std::convert::From, because it isn't defined for the same
// basic types as the `as` operator is... which kinda sucks. So, we have
// to implement the desired conversions ourselves.
//
// Since this would be hideously tedious, we can use a macro to speed things
// up a little.
trait CustomAs<T> {
fn custom_as(self) -> T;
}
macro_rules! custom_as_impl {
($src:ty:) => {};
($src:ty: $dst:ty) => {
impl CustomAs<$dst> for $src {
fn custom_as(self) -> $dst {
self as $dst
}
}
};
($src:ty: $dst:ty, $($rest:ty),*) => {
custom_as_impl! { $src: $dst }
custom_as_impl! { $src: $($rest),* }
};
}
// You could obviously list others, or do manual impls.
custom_as_impl! { u16: u16, u32, u64, i32, i64, f32, f64 }
fn main() {
let x: (u16, u16) = (1, 2);
let y: (f32, f32) = x.tuple_cast();
println!("{:?}", y);
}
没有内置的方法来执行此操作,但可以使用宏来执行此操作:
macro_rules! tuple_as {
($t: expr, ($($ty: ident),*)) => {
{
let ($($ty,)*) = $t;
($($ty as $ty,)*)
}
}
}
fn main() {
let t: (u8, char, isize) = (97, 'a', -1);
let other = tuple_as!(t, (char, i32, i8));
println!("{:?}", other);
}
打印 ('a', 97, -1)
.
该宏仅适用于在名称为单个标识符的类型之间进行转换(这就是 : ident
所指的),因为它会重用这些名称来绑定到源元组的元素,以便能够投他们。所有基本类型都是有效的单一标识符,因此它适用于那些。
这个版本处理了更多的案例Playground Example
原始来源:
由于匹配规则,对于单一类型转换只需使用 as_tuple!(expr, T)
或 as_tuple!(expr, (T))
其余部分与原始答案相同
macro_rules! tuple_as {
($t: expr, $ty: ident) => {{
let (a, b) = $t;
let a = a as $ty;
let b = b as $ty;
(a, b)
}};
($t: expr, ($ty: ident)) => {{
let (a, b) = $t;
let a = a as $ty;
let b = b as $ty;
(a, b)
}};
($t: expr, ($($ty: ident),*)) => {{
let ($($ty,)*) = $t;
($($ty as $ty,)*)
}}}
我想将 (u16, u16)
转换为 (f32, f32)
。这是我试过的:
let tuple1 = (5u16, 8u16);
let tuple2 = tuple1 as (f32, f32);
理想情况下,我想避免写作
let tuple2 = (tuple1.0 as f32, tuple1.1 as f32);
没有, 那里 是 没有。
不,你不能。这大致相当于 "can I cast all the fields in a struct to different types all at once?".
你可以写一个通用的扩展特征,它可以为你做这个转换,唯一的问题是我不相信有任何现有的通用"conversion"特征它还定义了 u16 -> f32
实现。
如果您真的想要一个执行此操作的函数,这里有一个您可以构建的尽可能最小的框架:
trait TupleCast<T> {
type Output;
fn tuple_cast(self) -> <Self as TupleCast<T>>::Output;
}
impl<T> TupleCast<T> for () {
type Output = ();
fn tuple_cast(self) -> <() as TupleCast<T>>::Output {
()
}
}
impl<S, T> TupleCast<T> for (S,) where S: CustomAs<T> {
type Output = (T,);
fn tuple_cast(self) -> <(S,) as TupleCast<T>>::Output {
(self.0.custom_as(),)
}
}
impl<S, T> TupleCast<T> for (S, S) where S: CustomAs<T> {
type Output = (T, T);
fn tuple_cast(self) -> <(S, S) as TupleCast<T>>::Output {
(self.0.custom_as(), self.1.custom_as())
}
}
// You would probably have more impls, up to some size limit.
// We can't use std::convert::From, because it isn't defined for the same
// basic types as the `as` operator is... which kinda sucks. So, we have
// to implement the desired conversions ourselves.
//
// Since this would be hideously tedious, we can use a macro to speed things
// up a little.
trait CustomAs<T> {
fn custom_as(self) -> T;
}
macro_rules! custom_as_impl {
($src:ty:) => {};
($src:ty: $dst:ty) => {
impl CustomAs<$dst> for $src {
fn custom_as(self) -> $dst {
self as $dst
}
}
};
($src:ty: $dst:ty, $($rest:ty),*) => {
custom_as_impl! { $src: $dst }
custom_as_impl! { $src: $($rest),* }
};
}
// You could obviously list others, or do manual impls.
custom_as_impl! { u16: u16, u32, u64, i32, i64, f32, f64 }
fn main() {
let x: (u16, u16) = (1, 2);
let y: (f32, f32) = x.tuple_cast();
println!("{:?}", y);
}
没有内置的方法来执行此操作,但可以使用宏来执行此操作:
macro_rules! tuple_as {
($t: expr, ($($ty: ident),*)) => {
{
let ($($ty,)*) = $t;
($($ty as $ty,)*)
}
}
}
fn main() {
let t: (u8, char, isize) = (97, 'a', -1);
let other = tuple_as!(t, (char, i32, i8));
println!("{:?}", other);
}
打印 ('a', 97, -1)
.
该宏仅适用于在名称为单个标识符的类型之间进行转换(这就是 : ident
所指的),因为它会重用这些名称来绑定到源元组的元素,以便能够投他们。所有基本类型都是有效的单一标识符,因此它适用于那些。
这个版本处理了更多的案例Playground Example
原始来源:
由于匹配规则,对于单一类型转换只需使用 as_tuple!(expr, T)
或 as_tuple!(expr, (T))
其余部分与原始答案相同
macro_rules! tuple_as {
($t: expr, $ty: ident) => {{
let (a, b) = $t;
let a = a as $ty;
let b = b as $ty;
(a, b)
}};
($t: expr, ($ty: ident)) => {{
let (a, b) = $t;
let a = a as $ty;
let b = b as $ty;
(a, b)
}};
($t: expr, ($($ty: ident),*)) => {{
let ($($ty,)*) = $t;
($($ty as $ty,)*)
}}}