Как создать тип, который можно преобразовать из всех других типов, используя From?

#rust

Вопрос:

Я хочу, чтобы мой тип MyError был конвертируемым из всех других типов. Я попытался сделать это следующим образом:

 impl<T> From<T> for MyError {
    fn from(_: T) -> Self {
        MyError::Unknown
    }
}
 

Но я получаю следующую ошибку:

 error[E0119]: conflicting implementations of trait `std::convert::From<MyError>` for type `MyError`
  --> src/main.rs:26:5
   |
26 |     impl<T> From<T> for MyError {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: conflicting implementation in crate `core`:
           - impl<T> From<T> for T;
 

Это имеет смысл , потому что один такой T обязательно MyError , и эта реализация охватывается impl<T> From<T> for T . В идеале я мог бы исключить MyError из T подобных:

 impl<T> From<T> for MyError where T != MyError
 

но очевидно, что это не сработает. Есть ли какой-нибудь способ выполнить то, что я пытаюсь сделать?

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

1. вы не можете этого сделать из-за пустой реализации.

2. Вы не можете этого сделать, так что, может быть, дайте нам дополнительную информацию о том, почему вы пытаетесь это сделать…

Ответ №1:

Учитывая именно то, что вы указали, вы можете достичь этого, используя auto_traits функции «Только ночью» и negative_impls «только ночью» следующим образом:

 #![feature(auto_traits, negative_impls)]

enum MyError {
    A,
    B,
    C,
    Unknown,
}


auto trait IsNotMyError {}

impl !IsNotMyError for MyError {}


impl<T: IsNotMyError> From<T> for MyError {
    fn from(_: T) -> Self {
        Self::Unknown
    }
}
 

Однако этот impl не очень полезен, для ? чего , я полагаю, вы его используете.

Предполагая , что вы получаете a Result<T, E> и хотите преобразовать E его в MyError::Unknown using ? , это не сработает:

 fn f<T, E>(f: impl FnOnce() -> Result<T, E>) -> Result<T, MyError> {
    let value = f()?;
    
    Ok(value)
}
 

Вы получите следующее сообщение об ошибке:

 error[E0277]: the trait bound `E: IsNotMyError` is not satisfied
   --> src/lib.rs:24:20
    |
24  |     let value = f()?;
    |                    ^ the trait `IsNotMyError` is not implemented for `E`
 

Это потому E , что может быть MyError , и тогда неясно, должна ли ошибка возврата быть просто E или MyError::Unknown .

Вместо этого рекомендуется просто сделать .map_err(|_| MyError::Unknown)? это, если вы хотите избавиться от ошибки, в отличие от ее реализации From<T> :

 fn f<T, E>(f: impl FnOnce() -> Result<T, E>) -> Result<T, MyError> {
    let value = f().map_err(|_| MyError::Unknown)?;
    
    Ok(value)
}
 

То есть, предполагая, что вы хотите удалить исходную ошибку, в противном случае просто оберните перечисление ошибок общим E и передайте ошибку обратно.

Вы можете найти более подробную информацию о функциях, описанных выше, в разделе «Нестабильная книга«.:

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

1. Я ценю подробное объяснение, спасибо!

2. Я был бы признателен за ссылку на источник, чтобы узнать больше об этих функциях.

3. @Stargateur Вы можете найти более подробную информацию о них в нестабильной книге : Автоматические черты и негативные последствия

4. мой плохой, я имею в виду в ответе, комментарий улетает