[英]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>
,但我們說T
被B
類型覆蓋,所以我們只取頂層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.