簡體   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