我正在嘗試實現一個錯誤枚舉,它可能包含與我們的某個特征相關的錯誤,如下所示: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>
無限大 - 但該錯誤與關于impl
s / 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
提交
取消