簡體   English   中英

為什么在關聯類型上無法識別除第一個之外的超特征邊界?

[英]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 += t2t += &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>

如果我們更改TraitAddAssign邊界的順序,則相反: 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之一,為什么不能識別另一個? 似乎最后一個界限是要被識別的界限。

我的第一個懷疑是這與動態調度有關。 我排除了它,因為即使在動態調度中邊界的順序也不重要。 我什至不認為它使用它,因為所有類型在編譯時使用單態化都是已知的。

我目前的懷疑是一個編譯器錯誤,當它是關聯類型時,類型檢查器不考慮特征邊界上的泛型。 很容易想象這樣一個特定的案例被忽視了。

這是怎么回事?

這是一個已知的錯誤(或幾個的組合):

  1. 沒有詳細說明相關類型的更高級別特征邊界 (#50346)
  2. where 子句僅針對超特征進行闡述,而不針對其他內容(#20671)
  3. 子特征中聲明的關聯類型的約束不會傳播。 (#32722)
  4. 無法識別的關聯類型綁定到另一個關聯類型 (#24159)

解決方法是在每個使用站點重新聲明邊界:

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM