Ошибки форматирования в общей реализации TryInto

Я пытаюсь создать общую реализацию TryFrom для объекта T всякий раз, когда T реализует TryFrom. Однако я изо всех сил пытаюсь пройти anyhow::Errors.

В приведенном ниже коде я могу преобразовать Generic<T> в ValueContainer при условии, что &usize: TryFrom<T>. Он почти делает то, что я хочу, но не позволяет мне правильно обрабатывать ошибки из &usize: TryFrom<T>.

#[cfg(test)]
mod question {
    use std::fmt::Debug;

    use anyhow::anyhow;

    #[derive(Debug)]
    struct Generic<T: Debug>(T);
    #[derive(Debug)]
    struct Foo(usize);
    #[derive(Debug)]
    struct ValueContainer<'a>(&'a usize);

    impl TryFrom<Foo> for &usize {
        type Error = anyhow::Error;

        fn try_from(value: Foo) -> Result<Self, Self::Error> {
            if value.0 > 5 {
                Ok(&5)
            } else {
                Err(anyhow!("Value must be bigger"))
            }
        }
    }

    impl<'a, T> TryFrom<Generic<T>> for ValueContainer<'a>
    where
        for<'b> &'b usize: TryFrom<T>,
        T: Debug,
        for<'b> anyhow::Error: From<<&'b usize as TryFrom<T>>::Error>,
    {
        type Error = anyhow::Error;

        fn try_from(value: Generic<T>) -> Result<Self, Self::Error> {
            // XXX: Can't do this?
            // let value: &usize = value.0.try_into().unwrap();
            match <&usize as TryFrom<T>>::try_from(value.0) {
                Ok(v) => Ok(ValueContainer(v)),
                Err(_) => {
                    // XXX: I would like this to be the error from the try_into above
                    // but there is an error `<&usize as TryFrom<T>>::Error` cannot be formatted with the default formatter`
                    return Err(anyhow!("Error converting type"));
                }
            }
        }
    }

    #[test]
    fn test_try_into() {
        let value = Generic(Foo(10));
        let value: Result<ValueContainer, anyhow::Error> = value.try_into();
        dbg!(&value);
        let value = Generic(Foo(2));
        let value: Result<ValueContainer, anyhow::Error> = value.try_into();
        dbg!(&value);
    }
}

Я не могу использовать value.try_into()? в своей реализации TryFrom<Generic<T>>. Раскомментирование let value: &usize = value.try_into()?; приводит к ошибке

error[E0271]: type mismatch resolving `<&usize as TryFrom<Generic<T>>>::Error == <&usize as TryFrom<T>>::Error`
   --> lib-doenetml-core/src/core/props/prop_view.rs:140:40
    |
140 |              let value: &usize = value.try_into()?;
    |                                        ^^^^^^^^ expected `Infallible`, found associated type
    |
    = note:         expected enum `Infallible`
            found associated type `<&usize as TryFrom<T>>::Error`
    = help: consider constraining the associated type `<&usize as TryFrom<T>>::Error` to `Infallible`
    = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html

Кажется, Использование дженериков TryInto с так или иначе::Error может быть уместно, и это вдохновило меня добавить for<'b> anyhow::Error: From<<&'b usize as TryFrom<T>>::Error>, но это, похоже, не сработало...

Есть идеи, как я могу разрешить value.try_into()? напрямую?

Почему ваш код не работает? Пожалуйста, добавьте полное сообщение об ошибке, например cargo build, к своему вопросу в виде отформатированного текста!

cafce25 14.03.2024 21:35

Обратите внимание, что лучше использовать Into и TryInto, чем From в границах, чтобы быть строго более общим.

Chayim Friedman 14.03.2024 22:07

Вы забыли добавить .0.

Chayim Friedman 14.03.2024 22:12

Компилятор, вероятно, сообщит вам, что именно нужно добавить, чтобы он скомпилировался.

cdhowie 15.03.2024 04:00

@cafce25 Приведенный выше код компилируется. Именно XXX в комментариях не работает при раскомментировании. Например, при раскомментировании первого я получаю ошибку error[E0271]: type mismatch resolving <&usize as TryFrom<Generic<T>>>::Error == <&usize as TryFrom<T>>::Error

Jason Siefken 15.03.2024 06:52

@ChayimFriedman Можете ли вы объяснить больше? Упомянутый вопрос stackoverflow.com/questions/72626885/… предполагает, что граница должна быть указана в терминах From, а не в терминах Into, особенно в отношении того, как Result работает.

Jason Siefken 15.03.2024 06:54

«полное сообщение об ошибке» — добавьте его.

cafce25 15.03.2024 07:33

@cafce25 cafce25 Я добавил к вопросу полное сообщение об ошибке.

Jason Siefken 16.03.2024 16:35

Если добавить забытый .0 (value.0.try_into()?) — работает. Вы, кажется, игнорируете то, что я сказал, поэтому я перепечатываю это здесь.

Chayim Friedman 16.03.2024 18:53

Поскольку вы, кажется, постоянно игнорируете мои комментарии или по каким-то причинам неправильно их интерпретируете, вот доказательство того, что то, что я предложил, работает: play.rust-lang.org/….

Chayim Friedman 16.03.2024 22:48

@ChayimFriedman Спасибо! Это действительно была ошибка. Я исправил это и обновил вопрос. Вроде value.0.try_into()? работает, но value.0.try_into().unwrap() выдаёт ошибку <&usize as TryFrom<T>>::Error doesn't implement Debug

Jason Siefken 16.03.2024 22:49

Это потому, что unwrap() требует реализации типа ошибки Debug. Добавьте привязку for<'b> <&'b usize as TryFrom<T>>::Error: Debug и всё заработает. Однако у меня сложилось впечатление, что вам нужен ?, а не unwrap(). В любом случае, этот вопрос следует закрыть, поскольку «вызван опечаткой».

Chayim Friedman 16.03.2024 22:51

@ChayimFriedman Вопрос не был вызван опечаткой. Я допустил опечатку при создании минимального примера выше, но в коде, из которого я его извлек, опечатки не было. Я хотел, чтобы оба ? и .unwrap() работали, но думал, что они оба не работают по одной и той же причине, поэтому я поставил в вопрос только один.

Jason Siefken 16.03.2024 23:02

Ах хорошо. Тогда действительно.

Chayim Friedman 16.03.2024 23:04
Как создавать пользовательские общие типы в Python (50/100 дней Python)
Как создавать пользовательские общие типы в Python (50/100 дней Python)
Помимо встроенных типов, модуль типизации в Python предоставляет возможность определения общих типов, что позволяет вам определять типы, которые могут...
0
14
80
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

? подойдет, если вы исправите опечатку и добавите .0.

unwrap() требует признака Debug для ошибки (поскольку он печатает его в случае сбоя), поэтому вам нужно добавить эту границу:

impl<'a, T> TryFrom<Generic<T>> for ValueContainer<'a>
where
    for<'b> &'b usize: TryFrom<T>,
    T: Debug,
    for<'b> anyhow::Error: From<<&'b usize as TryFrom<T>>::Error>,
    for<'b> <&'b usize as TryFrom<T>>::Error: Debug,
{
    type Error = anyhow::Error;

    fn try_from(value: Generic<T>) -> Result<Self, Self::Error> {
        // XXX: Can't do this?
        let value: &usize = value.0.try_into().unwrap();
        Ok(ValueContainer(value))
    }
}

Другие вопросы по теме