簡體   English   中英

我應該如何使用一個受我的特征綁定的通用參數為我的結構實現 From/Into?

[英]How should I implement From/Into for my struct with one generic parameter bound by my trait?

https://www.rustexplorer.com/b/pg3wqr

trait A {}

struct B<T: A>(T);

// this is ok
impl<T: A> From<T> for B<T> {
    fn from(t: T) -> Self { B(t) }
}

// this is not ok
impl<T: A> From<B<T>> for T {
    fn from(b: B<T>) -> Self { b.0 }
}

我得到:

錯誤[E0210]:類型參數T出現在第一個本地類型( B<T> )之前時,它必須被另一個類型覆蓋

這並沒有真正的幫助(搜索此錯誤消息也沒有)。 我想要實現的目標似乎很簡單。 為什么不允許這樣做,我該如何解決這些限制?

https://stackoverflow.com/a/39186717/4876553基本上都推薦了同樣的東西,沒有在impl上綁定,同樣的編譯方式失敗。

編輯:我不小心復制粘貼了我試圖解決這個問題的 WIP 版本; 固定回原來的例子。

Rust 的孤兒規則不允許這樣做。 確切的覆蓋語義很復雜(如果您有興趣,這篇文章是一個很好的起點),但基本思想是這樣的:

按順序獲取傳遞給impl的所有類型和 trait 名稱,從 trait 本身開始,然后是我們正在為其編寫impl的結構或枚舉,然后是任何類型 arguments。 所以用impl寫成

impl<T> MyTrait<Bar, Baz, T> for Foo

我們會寫MyTrait, Foo, Bar, Baz, T (其中T是一個類型變量)。

現在,在我們編寫的這個列表中,找到我們自己的 crate 中定義的名字。 如果 trait 是在我們自己的 crate 中定義的,那么這就是名稱。 如果Foo是,那就拿那個。 否則,繼續前進,直到找到一個。 如果當前 crate 中沒有定義名稱,則失敗,因為我們有一個孤立實例。 在這個例子中,假設MyTrait是在其他地方定義的,但Foo是我們自己的。 然后我們有

MyTrait, Foo, Bar, Baz, T
         ^^^

我們剛剛找到的名稱之前的任何內容都必須是具體的,即它不能是泛型類型參數。 在我們的示例中,唯一的類型參數是T ,它出現在Foo之后,所以沒問題。

(請注意,我也忽略了覆蓋類型。也就是說,出於孤立目的, &Foo上的 impl 被視為Foo上的 impl。這適用於引用、 Box和其他一些內置的類Box類型;它永遠不會適用於您自己定義的類型)

現在讓我們看看你的例子。 當我們添加 generics 時,事情變得更加復雜,我不會在這里討論 go 的所有混亂技術細節,所以我們會盡量保持簡單。

impl<T: A> From<T> for B<T>

在這里,特征是From ,我們正在實現的類型是B ,而From的類型參數是T 我們的清單是

From, B, T

請注意,雖然我們正在實現B<T> ,但我們說TB類型覆蓋,所以我們只取頂層B ,而不是里面的內容。

現在From是標准庫,所以我們不擁有它,但B在我們的板條箱中。 所以我們有

From, B, T
      ^

然后我們尋找通用 arguments。 這里唯一的類型參數是T ,它出現我們擁有的B之后,所以我們很好。

現在是另一個。

impl<T: A> From<B<T>> for T

和以前一樣,特征是From 第一個類型是T ,一個泛型類型參數。 然后B<T>是下一個。

From, T, B

同樣,我們寫B ,而不是B<T> ,因為我們只關心未覆蓋的類型

From是標准庫,而T是類型參數,所以B是我們在這里唯一擁有的東西。

From, T, B
         ^

但是在我們擁有的第一件事之前有一個類型參數T ,這是一個問題。 所以這因 Rust 的孤兒規則而失敗。

以這種方式編寫規則的原因是為了防止兩個同級 crate(即不知道彼此的 crate)意外實現沖突的實例。 如果我們允許

impl<T: A> From<B<T>> for T

那么有一天其他人可能會來寫

impl<T> From<T> for C

對於某些類型的C在他們自己的板條箱中。 他們完全有權這樣做: C是他們自己的類型,唯一的通用參數出現在其特征參數列表中的C之后 但是impl From<B<C>> for C有兩個候選解決方案。 (請注意,特征界限,即T: A被考慮得更晚了,此時不考慮,因為這只會使已經很復雜的特征解析問題完全站不住腳)。

在您的實現中,您正在使用from(u: U) 您編寫代碼的方式U不是泛型類型,因為您沒有在 impl 塊中聲明它。 唯一可用的泛型類型是T 在 function 中,您需要使用 B 類型的參數。您已將 B 聲明為元組結構,其 1 且唯一的字段是必須實現特征 A 的泛型類型 T。因此,要從 B 中取出 t需要調用 b.0 這是從元組結構中獲取值的語法。 您還需要使該字段可訪問,因此您需要將結構定義更改為

struct B<T: A>(pub T);

然后將 impl 塊更改為此

impl<T: A> From<B<T>> for T {
    fn from(b: B) -> T { 
        b.0 
    }
}

function 定義也可以返回Self例如fn from(b: B) -> Self {...}因為在這個 impl 塊中 Self 與 T 相同。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM