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 版本;固定回原來的例子。
uj5u.com熱心網友回復:
Rust 的孤兒規則不允許這樣做。確切的覆寫語意很復雜(如果您有興趣,這篇文章是一個很好的起點),但基本思想是這樣的:
按順序將所有型別和特征名稱傳遞給 an impl,從特征本身開始,然后是我們正在撰寫的結構或列舉implfor,然后是任何型別引數。所以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 on 被認為是一個 impl on Foo。這適用于參考、Box和其他幾種類似內置的Box型別;它從不適用于您自己定義的型別)
現在讓我們看看你的例子。當我們添加泛型時,事情會變得更加復雜,我不會在這里討論所有混亂的技術細節,所以我們會盡量保持簡單。
impl<T: A> From<T> for B<T>
在這里,特征是From,我們正在實作的型別是B,我們的型別引數From是T。我們的清單是
From, B, T
請注意,雖然我們正在實作 for B<T>,但我們說T被型別覆寫,B所以我們只取頂層B,而不是里面的內容。
現在From是標準庫,所以我們不擁有它,但B在我們的 crate 中。所以我們有
From, B, T
^
然后我們尋找通用引數。這里唯一的型別引數是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他們的 trait 引數串列之后。但是有兩個候選解決方案impl From<B<C>> for C。(請注意,特征界限,即T: A在很久以后才考慮到,此時不考慮,因為這只會使已經很復雜的特征決議問題完全站不住腳)。
uj5u.com熱心網友回復:
編輯。由于孤兒規則,這仍然不起作用。Silvio 的回答也解釋了為什么這段代碼不起作用。
下面的舊評論
在您的實作中,您正在使用
from(u: U). 您撰寫代碼的方式U不是泛型型別,因為您沒有在 impl 塊中宣告它。唯一可用的泛型型別是T. 在函式中,您需要使用 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>) -> T {
b.0
}
}
函式定義也可以回傳,
Self例如fn from(b: B) -> Self {...},因為在這個 impl 塊中 Self 與 T 相同。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/510463.html
標籤:仿制药锈
