繁体   English   中英

将特征边界应用于关联类型

[英]Apply trait bounds to associated type

假设我有这样的特征:

trait InternalError {
    fn internal(error: String) -> Self;
}

如果我想在函数中使用它,我可以这样做:

struct MyU16(pub u16);

fn my_try_from<E: InternalError>(value: u32) -> Result<MyU16, E> {
    if value < u16::MAX as u32 {
        Ok(MyU16(value as u16))
    } else {
        Err(E::internal("invalid".to_string()))
    }
}

这很好用

现在想象一下,我想使用TryFrom ,而不是使用我自己的函数:

impl<E: InternalError> TryFrom<u32> for MyU16 {
    type Error = E;

    fn try_from(value: u32) -> Result<Self, Self::Error> {
        if value < u16::MAX as u32 {
            Ok(MyU16(value as u16))
        } else {
            Err(E::internal("invalid".to_string()))
        }
    }
}

然而,这不起作用。 我尝试了各种不同的方式来表达这一点,但我无法弄清楚如何说“这个 TryFrom impl,在错误的情况下,返回一些 impls InternalError 的东西”。

任何有关如何正确执行此操作的建议将不胜感激。 谢谢!

这个 TryFrom impl,在错误的情况下,返回一些 impls InternalError

TryFrom想在编译时知道返回了什么样的错误。 您似乎想在运行时决定类型。

假设FirstErrorSecondError都实现了InternalError

在这种情况下

impl TryFrom<u32> for MyU16 {
    type Error = FirstError;

    fn try_from(value: u32) -> Result<Self, FirstError> {
        /*...*/
    }
}

会编译,但当然try_from只能返回FirstError

但是,如果您想在运行时在FirstErrorSecondError之间做出决定。 相关的错误类型(不是特征)需要能够同时包含两者。

impl TryFrom<u32> for MyU16 {
    type Error = Box<dyn InternalError>;

    fn try_from(value: u32) -> Result<Self, Box<dyn InternalError>> {
        /*...*/
        Box::new(FirstError::internal("invalid".to_string()))
    }
}

这也暗示了为什么enum是 Rust 中表示错误的惯用方式:通常你在编译时不知道会出现什么问题。 因此,一个可以列出所有状态的enum可以让用户清楚地知道可能出现的问题,并且在许多情况下,您可以在没有额外堆分配的情况下创建错误。

它无法编译的原因是impl声明中的类型参数必须出现在实现类型impl<T> Foo<T> )或实现的特征impl<T> MyTrait<T> for Foo )。 您不能只impl<T> for Foo并且只在impl块中再次提及T

正如扩展错误所暗示的那样,有一种解决方法将幻像类型引入实现类型,但您可能不喜欢它使您的代码看起来如何:

use std::marker::PhantomData;

struct MyU16<T>(pub u16, PhantomData<T>);

impl<E: InternalError> TryFrom<u32> for MyU16<E> {
    type Error = E;

    fn try_from(value: u32) -> Result<Self, Self::Error> {
        if value < u16::MAX as u32 {
            Ok(MyU16(value as u16, PhantomData))
        } else {
            Err(E::internal("invalid".to_string()))
        }
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM