[英]Why are supertrait bounds other than the first not recognized on an associated type?
此代碼段在 Rust 1.26.1 中有效:
use std::ops::AddAssign;
trait Trait
where
for<'a> Self: AddAssign<Self> + AddAssign<&'a Self> + Sized,
{
}
trait Trait2 {
type Associated: Trait;
fn method(u32) -> Self::Associated;
}
fn func<T2: Trait2>() {
let mut t = T2::method(1);
let t2 = T2::method(2);
t += &t2;
}
請注意, Trait
實現了AddAssign<Self>
和AddAssign<&'a Trait>
(按這個順序,這在后面很重要)。 因此,在func
我們知道t += t2
和t += &t2
都應該是有效的。 正如在操場上看到的, t += &t2
是有效的,但使用t += t2
不是:
error[E0308]: mismatched types
--> src/main.rs:19:10
|
19 | t += t2;
| ^^
| |
| expected reference, found associated type
| help: consider borrowing here: `&t2`
|
= note: expected type `&<T2 as Trait2>::Associated`
found type `<T2 as Trait2>::Associated`
我讀到這個錯誤是因為編譯器沒有認識到AddAssign<Self>
是為T::Associated
,這顯然是錯誤的,因為它實現了Trait
,它需要AddAssign<Self>
。
如果我們更改Trait
上AddAssign
邊界的順序,則相反: t += t2
有效而t += &t2
無效。
該問題的快速解決方法是使func
對兩個特征都通用:
fn func<T: Trait, T2: Trait2<Associated = T>>() {
let mut t = T2::method(1);
let t2 = T2::method(2);
t += t2;
}
這不應該是必要的; 編譯器可以識別AddAssign
之一,為什么不能識別另一個? 似乎最后一個界限是要被識別的界限。
我的第一個懷疑是這與動態調度有關。 我排除了它,因為即使在動態調度中邊界的順序也不重要。 我什至不認為它使用它,因為所有類型在編譯時使用單態化都是已知的。
我目前的懷疑是一個編譯器錯誤,當它是關聯類型時,類型檢查器不考慮特征邊界上的泛型。 很容易想象這樣一個特定的案例被忽視了。
這是怎么回事?
這是一個已知的錯誤(或幾個的組合):
解決方法是在每個使用站點重新聲明邊界:
fn func<T2>()
where
T: Trait2,
T::Associated: Trait,
{
let mut t = T::method(1);
let t2 = T::method(2);
t += &t2;
t += t2;
}
當類型系統從其臨時實現轉移到Chalk 時,應該解決這個問題, Chalk是一個更原則性的解決方案,用於解決復雜類型系統創建的問題類型。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.