Я пытаюсь создать общую реализацию 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()? напрямую?
Обратите внимание, что лучше использовать Into и TryInto, чем From в границах, чтобы быть строго более общим.
Вы забыли добавить .0.
Компилятор, вероятно, сообщит вам, что именно нужно добавить, чтобы он скомпилировался.
@cafce25 Приведенный выше код компилируется. Именно XXX в комментариях не работает при раскомментировании. Например, при раскомментировании первого я получаю ошибку error[E0271]: type mismatch resolving <&usize as TryFrom<Generic<T>>>::Error == <&usize as TryFrom<T>>::Error
@ChayimFriedman Можете ли вы объяснить больше? Упомянутый вопрос stackoverflow.com/questions/72626885/… предполагает, что граница должна быть указана в терминах From, а не в терминах Into, особенно в отношении того, как Result работает.
«полное сообщение об ошибке» — добавьте его.
@cafce25 cafce25 Я добавил к вопросу полное сообщение об ошибке.
Если добавить забытый .0 (value.0.try_into()?) — работает. Вы, кажется, игнорируете то, что я сказал, поэтому я перепечатываю это здесь.
Поскольку вы, кажется, постоянно игнорируете мои комментарии или по каким-то причинам неправильно их интерпретируете, вот доказательство того, что то, что я предложил, работает: play.rust-lang.org/….
@ChayimFriedman Спасибо! Это действительно была ошибка. Я исправил это и обновил вопрос. Вроде value.0.try_into()? работает, но value.0.try_into().unwrap() выдаёт ошибку <&usize as TryFrom<T>>::Error doesn't implement Debug
Это потому, что unwrap() требует реализации типа ошибки Debug. Добавьте привязку for<'b> <&'b usize as TryFrom<T>>::Error: Debug и всё заработает. Однако у меня сложилось впечатление, что вам нужен ?, а не unwrap(). В любом случае, этот вопрос следует закрыть, поскольку «вызван опечаткой».
@ChayimFriedman Вопрос не был вызван опечаткой. Я допустил опечатку при создании минимального примера выше, но в коде, из которого я его извлек, опечатки не было. Я хотел, чтобы оба ? и .unwrap() работали, но думал, что они оба не работают по одной и той же причине, поэтому я поставил в вопрос только один.
Ах хорошо. Тогда действительно.

? подойдет, если вы исправите опечатку и добавите .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))
}
}
Почему ваш код не работает? Пожалуйста, добавьте полное сообщение об ошибке, например
cargo build, к своему вопросу в виде отформатированного текста!