我想要一个接受各种类型的函数,这些类型可以转换为我的特定类型。在类似的情况下,我会使用std::convert::Into
(或std::convert::From
):
pub struct MyThing;
impl<'a> Into<MyThing> for &'a str {
fn into(self) -> MyThing {
MyThing
}
}
fn main() {}
作为一个额外的问题,在我的特定情况下,转换可能会失败。通常,我会使用Result
来表示可能失败的操作。将两个概念结合在一起:
pub struct MyThing;
pub struct Error;
impl<'a> Into<Result<MyThing, Error>> for &'a str {
fn into(self) -> Result<MyThing, Error> {
if self.len() % 2 == 0 {
Ok(MyThing)
} else {
Err(Error)
}
}
}
fn main() {}
不幸的是,这似乎与相干规则相冲突:
error: the impl does not reference any types defined in this crate;
only traits defined in the current crate can be implemented for
arbitrary types [E0117]
我看到我可以创造我自己的特色:
struct MyThing;
struct Error;
trait IntoMyThing {
fn into(self) -> Result<MyThing, Error>;
}
impl<'a> IntoMyThing for &'a str {
fn into(self) -> Result<MyThing, Error> {
if self.len() % 2 == 0 {
Ok(MyThing)
} else {
Err(Error)
}
}
}
fn main() {}
或者更一般的特征:
struct MyThing;
struct Error;
trait MaybeInto<T, E> {
fn into(self) -> Result<T, E>;
}
impl<'a> MaybeInto<MyThing, Error> for &'a str {
fn into(self) -> Result<MyThing, Error> {
if self.len() % 2 == 0 {
Ok(MyThing)
} else {
Err(Error)
}
}
}
fn main() {}
但是有没有办法重用标准库中的组件来实现我的目标呢?
由于一致性规则,这是不可能的,这使得这样的事情非常不方便,因为除非为Result
或&str
中的一种类型创建一个新类型,否则无法做到这一点。更多信息请参见rfc# 1023。
简而言之,根据RFC规定的新规则,您不能为非crate本地的类型实现非crate本地的trait。
- 修改孤儿规则,使远程trait的imps需要一个本地类型,要么是当前crate
LT = LocalTypeConstructor<...>
中定义的struct/enum/trait,要么是对本地类型LT = ... | < | &mut LT
的引用。
因此,由于您没有在crate中创建Into
trait,也没有创建Result
类型,因此您会得到此错误。创建新类型解决了这个问题,因为它基本上是将非局部类型包装在局部类型中。