我如何使用std :: convert :: Into来转换可能失败的东西?

时间:2015-05-19 00:55:21

标签: rust

我想要一个接受各种类型的函数,这些类型可以转换为我的特定类型。在类似的情况下,我会使用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() {}

但有没有办法重用标准库中的组件来实现我的目标?

1 个答案:

答案 0 :(得分:1)

这是不可能的,因为一致性规则,这使得这样的事情非常不方便,因为你不能这样做,除非你为其中一种类型创建一个新类型,Result&str。有关详细信息,请参阅RFC #1023

简而言之,根据该RFC规定的新规则,您无法为包不是本地的类型实现非本地包含的特征。

  
      
  1. 修改孤立规则,以便远程特征的impl需要本地类型,该类型是当前包LT = LocalTypeConstructor<...>中定义的结构/枚举/特征,或者是对本地类型LT = ... | &LT | &mut LT的引用。 / LI>   

因此,由于您未在包中创建Into特征,也未在Result类型中创建特征,因此会出现此错误。创建新类型会修复此问题,因为它基本上将非本地类型包装在本地类型中。