我的项目中有一个结构,该结构在逻辑上与来自不同板条箱的A结构相关。B两者内部都有一个可选的子结构 ( C/ D)。
假设对于这个例子,他们有这个结构定义:
struct D {
name: Option<String>
}
struct B {
spec: Option<D>
}
struct C {
name: Option<String>
}
struct A {
spec: Option<C>
}
Run Code Online (Sandbox Code Playgroud)
现在我想将Into-trait实现A为B:
impl Into<D> for C {
fn into(self) -> D {
D {
name: self.name
}
}
}
impl Into<B> for A {
fn into(self) -> B {
B {
spec: self.spec.into()
}
}
}
Run Code Online (Sandbox Code Playgroud)
但 Rust 不允许这样做:
error[E0277]: the trait bound `std::option::Option<D>: From<std::option::Option<C>>` is not satisfied
--> src\model\k8s.rs:615:29
|
615 | spec: self.spec.into()
| ^^^^ the trait `From<std::option::Option<C>>` is not implemented for `std::option::Option<D>`
|
= help: the following implementations were found:
<std::option::Option<&'a T> as From<&'a std::option::Option<T>>>
<std::option::Option<&'a mut T> as From<&'a mut std::option::Option<T>>>
<std::option::Option<&'a tracing_core::span::Id> as From<&'a tracing::span::EnteredSpan>>
<std::option::Option<&'a tracing_core::span::Id> as From<&'a tracing::span::Span>>
and 10 others
= note: required because of the requirements on the impl of `Into<std::option::Option<D>>` for `std::option::Option<C>`
Run Code Online (Sandbox Code Playgroud)
尽管我提供了一个自定义实现,但Into它只C检查From. 我无法提供D另一个板条箱。我必须这样写:
spec: if let Some(v) = self.spec { Some(v.into()) } else { None }
Run Code Online (Sandbox Code Playgroud)
现在的问题是:我缺少更好的方法吗?如果不是,为什么into()选项这么麻烦?
问题是您调用的是Into::into类型而不是( )Option<C>所保存的类型。OptionC
您可以使用Option::map对 的内部类型进行操作的方法Option:
impl Into<B> for A {
fn into(self) -> B {
B {
spec: self.spec.map(Into::into)
}
}
}
Run Code Online (Sandbox Code Playgroud)
标准库中没有毯子impl<T, U: Into<T>> Into<Option<T>> for Option<U>(或From等效物),这就是为什么您不能使用Into特征直接转换Option<T>为Option<U>,Option而必须依赖Option::map或其他方式(如您的最后一个片段)来提取内部类型。