Ржавчина В-Черта на опциях

#rust

Вопрос:

В моем проекте есть структура A , которая логически связана со структурой B из другого ящика. Оба имеют внутреннюю необязательную подструктуру ( C / D ).

Допустим, для этого примера у них есть такое определение структуры:

 
struct D {
    name: Option<String>
}

struct B {
    spec: Option<D>
}

struct C {
    name: Option<String>
}

struct A {
    spec: Option<C>
}
 

Теперь я хочу внедрить Into -черту в 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()
    }
  }
}
 

Но ржавчина этого не позволяет:

 error[E0277]: the trait bound `std::option::Option<D>: From<std::option::Option<C>>` is not satisfied
   --> srcmodelk8s.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<amp;'a T> as From<amp;'a std::option::Option<T>>>
              <std::option::Option<amp;'a mut T> as From<amp;'a mut std::option::Option<T>>>
              <std::option::Option<amp;'a tracing_core::span::Id> as From<amp;'a tracing::span::EnteredSpan>>
              <std::option::Option<amp;'a tracing_core::span::Id> as From<amp;'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>`
 

Хотя я предоставляю пользовательскую реализацию для Into on C, она проверяет только From . Который я не могу предоставить, так как D-это еще один ящик.

Я должен написать это:

 spec: if let Some(v) = self.spec { Some(v.into()) } else { None }
 

Теперь вопрос:
Есть ли лучший способ, которого мне не хватает?
Если нет: почему это так хлопотно с into() вариантами?

Комментарии:

1. A C Определены ли и в вашем ящике, в то время B как и D определены в другом ящике?

2. @Sven: Да, A amp; C-это мой собственный код, B amp; D-это то, что мне нужно для библиотеки, которую я использую

Ответ №1:

Проблема в том, что вы вызываете Into::into Option<C> тип, а не тип Option , который удерживает ( C ).

Вы можете использовать Option::map метод, который работает с внутренним типом Option :

 impl Into<B> for A {
  fn into(self) -> B {
    B {
      spec: self.spec.map(Into::into)
    }
  }
}
 

В стандартной библиотеке нет общего impl<T, U: Into<T>> Into<Option<T>> for Option<U> (или From эквивалентного), поэтому вы не можете использовать Into свойство для Option<T> превращения Option<U> непосредственно в Option и должны полагаться Option::map или каким-либо другим способом (например, ваш последний фрагмент) извлекать внутренний тип вместо этого.