我正在嘗試實現一個錯誤枚舉,它可能包含與我們的某個特征相關的錯誤,如下所示:trait Storage {
type Error;}enum MyError<S: Storage> {
StorageProblem(S::Error),}我還試圖實現From特性以允許MyError從一個實例構建Storage::Error:impl<S: Storage> From<S::Error> for MyError<S> {
fn from(error: S::Error) -> MyError<S> {
MyError::StorageProblem(error)
}}但是這無法編譯:error[E0119]: conflicting implementations of trait `std::convert::From<MyError<_>>` for type `MyError<_>`:
--> src/lib.rs:9:1
|
9 | impl<S: Storage> From<S::Error> for MyError<S> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: conflicting implementation in crate `core`:
- impl<T> std::convert::From<T> for T;我不明白為什么編譯器認為這已經實現了。錯誤消息告訴我已經有一個From<MyError<_>>(有)的實現,但我不想在這里實現 - 我正在嘗試實現,From<S::Error>并且MyError與S::Error我所看到的類型不同。我是否遺漏了仿制藥的基本內容?使用泛型類型時,如何實現“From”的沖突?
2 回答
小唯快跑啊
TA貢獻1863條經驗 獲得超2個贊
這里的問題是有人可能會實現,Storage以便From你寫的impl與標準庫中的impl重疊impl<T> From<T> for T(也就是說,任何東西都可以轉換為自身)。
特別,
struct Tricky;impl Storage for Tricky {
type Error = MyError<Tricky>;}(這里的設置意味著這實際上不是編譯 - MyError<Tricky>無限大 - 但該錯誤與關于impls / coherence /重疊的推理無關,實際上小的改變MyError可以使其編譯而不改變基本問題,例如添加一個Box像StorageProblem(Box<S::Error>),。)
如果我們用你的impl Tricky代替S,我們得到:
impl From<MyError<Tricky>> for MyError<Tricky> {
...}這impl與使用T== 的自轉換完全匹配MyError<Tricky>,因此編譯器不知道選擇哪一個。Rust編譯器避免了這樣的情況,而不是進行任意/隨機選擇,因此必須拒絕原始代碼,因為存在這種風險。
這種一致性限制肯定會令人煩惱,并且是專業化是一個備受期待的特性的原因之一:本質上允許手動指示編譯器如何處理重疊......至少,當前受限形式的擴展之一允許這樣做。
繁星淼淼
TA貢獻1775條經驗 獲得超11個贊
一致性問題的解決方法是使用Result::map_err自己執行轉換。然后,您可以使用末尾Result帶有try!或?:
fn example<S: Storage>(s: S) -> Result<i32, MyError<S>> {
s.do_a_thing().map_err(MyError::StorageProblem)?;
Ok(42)}當存在具有相同底層的錯誤變體時,此解決方案也很有用Error,例如,如果要分離“文件打開”和“文件讀取”錯誤,兩者都是io::Error。
添加回答
舉報
0/150
提交
取消
