尽可能实现 Into,否则使用 TryInto
Implementing Into when possible and using TryInto otherwise
我有一个结构:
pub struct Point2D<T>(pub T, pub T);
我希望能够:
- (A) 用
.into
将 Point2D<T>
变成 (T, T)
- (B) 如果
A
实现 TryInto<B>
,则将带有 .tryInto
的 Point2D<A>
转换为 (B, B)
我可以实现(A):
impl<T> std::convert::Into<(T, T)> for Point2D<T> {
fn into(self) -> (T, T) {
(self.0, self.1)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn into() {
let a: Point2D<u32> = Point2D(42, 42);
let a_into :(u32, u32) = a.into();
let b: (u32, u32) = (42, 42);
assert_eq!(a_into, b);
}
}
我可以实现(B):
#[derive(Debug)]
pub enum PointIntoError<T> {
ErrorInX(T),
ErrorInY(T),
}
impl<FromType, ToType> TryInto<(ToType, ToType)> for Point2D<FromType>
where FromType: TryInto<ToType>,
FromType: Copy {
type Error = PointIntoError<FromType>;
fn try_into(self) -> Result<(ToType, ToType), Self::Error> {
let x_ = self.0.try_into();
let y_ = self.0.try_into();
match x_ {
Ok(x) => {
match y_ {
Ok(y) => Ok((x, y)),
_ => Result::Err(PointIntoError::ErrorInY(self.1))
}
}
_ => Result::Err(PointIntoError::ErrorInX(self.0))
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn try_into() {
let a: Point2D<u32> = Point2D(400, 400);
let a_into :(u16, u16) = a.try_into().expect("Could not convert to tuple of u16");
let b: (u16, u16) = (400, 400);
assert_eq!(a_into, b);
}
#[test]
#[should_panic]
fn try_into_fail() {
let a: Point2D<u32> = Point2D(400, 400);
let a_into :(u8, u8) = a.try_into().expect("Could not convert to tuple of u8");
}
}
当 运行 单独时,两个测试都通过了。但是,当我尝试编译两个 impl
时,我得到:
error[E0119]: conflicting implementations of trait `std::convert::TryInto<(_, _)>` for type `Point2D<_>`:
--> src/lib.rs:31:1
|
31 | / impl<FromType, ToType> TryInto<(ToType, ToType)> for Point2D<FromType>
32 | | where FromType: TryInto<ToType>,
33 | | FromType: Copy {
34 | | type Error = PointIntoError<FromType>;
... |
49 | | }
50 | | }
| |_^
|
= note: conflicting implementation in crate `core`:
- impl<T, U> std::convert::TryInto<U> for T
where U: TryFrom<T>;
error: aborting due to previous error
For more information about this error, try `rustc --explain E0119`.
该错误不是特别有用,但我猜测对于实现 Into
的结构,存在某种针对 TryInto
的默认实现,因此我无法同时定义两者。
支持 Into
有意义的转换和 TryInto
转换的最惯用的方法是什么?我想我总是可以 .tryInto
和 .expect
当我确定类型匹配但看起来不整齐时。
I'm guessing there's some sort of default implementation for TryInto for structs that implement Into, and hence I cannot define both at the same time.
这是正确的,更具体地说,对于任何实现 Into
的结构都有 TryFrom
的全面实现(对于任何实现 From
的结构都是全面实现的):https://doc.rust-lang.org/std/convert/trait.TryFrom.html#impl-TryFrom%3CU%3E
What is the most idiomatic way to support both Into conversion when it makes sense and TryInto conversion? I suppose I could always .tryInto and .expect when I know for sure that the types match but it doesn't seem neat.
我认为最惯用的方法是将您的 Into
实现转换为普通方法,例如.into_tuple()
,这是一个相当常见的模式,例如 slice::into_vec
或 String::into_boxed_str
.
我有一个结构:
pub struct Point2D<T>(pub T, pub T);
我希望能够:
- (A) 用
.into
将 - (B) 如果
A
实现TryInto<B>
,则将带有
Point2D<T>
变成 (T, T)
.tryInto
的 Point2D<A>
转换为 (B, B)
我可以实现(A):
impl<T> std::convert::Into<(T, T)> for Point2D<T> {
fn into(self) -> (T, T) {
(self.0, self.1)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn into() {
let a: Point2D<u32> = Point2D(42, 42);
let a_into :(u32, u32) = a.into();
let b: (u32, u32) = (42, 42);
assert_eq!(a_into, b);
}
}
我可以实现(B):
#[derive(Debug)]
pub enum PointIntoError<T> {
ErrorInX(T),
ErrorInY(T),
}
impl<FromType, ToType> TryInto<(ToType, ToType)> for Point2D<FromType>
where FromType: TryInto<ToType>,
FromType: Copy {
type Error = PointIntoError<FromType>;
fn try_into(self) -> Result<(ToType, ToType), Self::Error> {
let x_ = self.0.try_into();
let y_ = self.0.try_into();
match x_ {
Ok(x) => {
match y_ {
Ok(y) => Ok((x, y)),
_ => Result::Err(PointIntoError::ErrorInY(self.1))
}
}
_ => Result::Err(PointIntoError::ErrorInX(self.0))
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn try_into() {
let a: Point2D<u32> = Point2D(400, 400);
let a_into :(u16, u16) = a.try_into().expect("Could not convert to tuple of u16");
let b: (u16, u16) = (400, 400);
assert_eq!(a_into, b);
}
#[test]
#[should_panic]
fn try_into_fail() {
let a: Point2D<u32> = Point2D(400, 400);
let a_into :(u8, u8) = a.try_into().expect("Could not convert to tuple of u8");
}
}
当 运行 单独时,两个测试都通过了。但是,当我尝试编译两个 impl
时,我得到:
error[E0119]: conflicting implementations of trait `std::convert::TryInto<(_, _)>` for type `Point2D<_>`:
--> src/lib.rs:31:1
|
31 | / impl<FromType, ToType> TryInto<(ToType, ToType)> for Point2D<FromType>
32 | | where FromType: TryInto<ToType>,
33 | | FromType: Copy {
34 | | type Error = PointIntoError<FromType>;
... |
49 | | }
50 | | }
| |_^
|
= note: conflicting implementation in crate `core`:
- impl<T, U> std::convert::TryInto<U> for T
where U: TryFrom<T>;
error: aborting due to previous error
For more information about this error, try `rustc --explain E0119`.
该错误不是特别有用,但我猜测对于实现 Into
的结构,存在某种针对 TryInto
的默认实现,因此我无法同时定义两者。
支持 Into
有意义的转换和 TryInto
转换的最惯用的方法是什么?我想我总是可以 .tryInto
和 .expect
当我确定类型匹配但看起来不整齐时。
I'm guessing there's some sort of default implementation for TryInto for structs that implement Into, and hence I cannot define both at the same time.
这是正确的,更具体地说,对于任何实现 Into
的结构都有 TryFrom
的全面实现(对于任何实现 From
的结构都是全面实现的):https://doc.rust-lang.org/std/convert/trait.TryFrom.html#impl-TryFrom%3CU%3E
What is the most idiomatic way to support both Into conversion when it makes sense and TryInto conversion? I suppose I could always .tryInto and .expect when I know for sure that the types match but it doesn't seem neat.
我认为最惯用的方法是将您的 Into
实现转换为普通方法,例如.into_tuple()
,这是一个相当常见的模式,例如 slice::into_vec
或 String::into_boxed_str
.