簡體   English   中英

終身省略是否適用於特質的方法?

[英]Does lifetime elision work for methods in trait impls?

有了這個問題,我正在尋找那些在這方面有更多知識的人的反饋。 我絕不是專家。 所以我不妨提前問我的問題:我的推理是否正確?

問題

根據這里關於SO 的問題答案 ,我很困惑地看到在實施特征方法時終生沒有了:

impl<'a, 'b, T> PartialEq<RefEquality<'b, T>> for RefEquality<'a, T> {
    fn eq(&self, other: &RefEquality<T>) -> bool {
        self.0 as *const T == other.0 as *const T
    }
}

這里,在方法簽名中,在other類型上省略了生命周期'b 這是有效的,也是正確的。 我期望它是&RefEquality<'b, T> ,因為類型是正確的。 畢竟,這里的'b是必不可少的:生命必須與'a不同。 如果沒有,那就太限制了:實現只適用於另一個與Self相同的RefEquality<T> 所以這些顯然是不同的語義。 編譯器如何推斷出正確的生命周期?

終身消費照顧它

可以省略函數簽名的生命周期,但不能在impl塊上省略它們。 在那里,必須完全指定類型,包括命名生命周期。

另一方面,在eq()方法上,我能夠在其他類型注釋中忽略生命周期。 實際上,編譯器然后為它插入任意生命周期,這明顯不同於'a 這就是為什么這樣做同時保持相同語義的原因:

impl<'a, 'b, T> PartialEq<RefEquality<'b, T>> for RefEquality<'a, T> {
    fn eq<'c>(&self, other: &RefEquality<'c, T>) -> bool {
        self.0 as *const T == other.0 as *const T
    }
}

在這里,我為該方法引入了一個任意的生命周期'c ,這與生命周期省略時的編譯器基本相同。

在我的特質impl中命名一輩子'b只是聲明它必須與'a (我也沒有以任何方式鏈接它們)不同。 從邏輯上講,這不起作用:

impl<'a, 'b, T> PartialEq<RefEquality<'b, T>> for RefEquality<'a, T> {
    fn eq(&self, other: &RefEquality<'a, T>) -> bool {
        self.0 as *const T == other.0 as *const T
    }
}

我在impl中說過類型會有所不同(基於它們的生命周期),但現在實際的eq()實現說它們是相同的。 這會導致預期的類型錯誤。

如果我希望生命時間平等怎么辦? 在這種情況下,我仍然可以使用生命周期省略,還是編譯器會插入任意生命周期並報告類型錯誤? 事實證明,推理在這里也能正常工作:

impl<'a, T> PartialEq<RefEquality<'a, T>> for RefEquality<'a, T> {
    fn eq(&self, other: &RefEquality<T>) -> bool {
        self.0 as *const T == other.0 as *const T
    }
}

省略的生命周期將被推斷為'a ,保持RefEquality<T>類型必須具有相同生命期望的期望語義。

讓我們看看rustc的過程,以確定提供的impl方法是否對應於特征中聲明的簽名。

在代碼中的位置compare_impl_methodlibrustc_typeck/check/compare_method.rs ,它的很好的注釋,但連評論都難以用於那些沒有編譯器的黑客。

我不是編譯器開發人員,所以以下是基於我的生銹經驗和解釋!

特征中的聲明對應於特定的函數類型,並且impl塊中的定義被解析為其自己的函數類型。

對於這個問題,我認為只有類型檢查的結論才是重要的:

  • impl函數是特質函數的子類型嗎?”

對我進行分類

如果S是T的子類型,則子類型關系通常寫為S <:T,意味着可以在期望類型為T的項的上下文中安全地使用類型S的任何項。

這聽起來很合理。 我們希望impl塊定義一個可以安全使用的函數,就好像它是在trait中聲明的函數一樣。

情況1

這是完整的終生案例,但明確說明。 我已經用恐慌替換了所有方法體,以強調函數簽名檢查完全不受函數體的影響。

impl<'a, 'b, T> PartialEq<RefEquality<'b, T>> for RefEquality<'a, T> {
    fn eq<'c>(&self, other: &RefEquality<'c, T>) -> bool {
        panic!()
    }
}

該特征需要一個類型的函數:

fn(&RefEquality<'a, T>, &RefEquality<'b, T>)

您提供類型的功能:

fn<'c>(&RefEquality<'a, T>, &RefEquality<'c, T>)

看起來所提供的impl比所需的“更通用”。 使用'c == 'b ,則函數的類型相同。

它是預期類型的​​子類型,因為我們總是可以安全地使用fn<'c>版本。

案例2

對於你的第二個例子,那個沒有編譯:

impl<'a, 'b, T> PartialEq<RefEquality<'b, T>> for RefEquality<'a, T> {
    fn eq(&self, other: &RefEquality<'a, T>) -> bool {
        panic!()
    }
}

你可以添加一個綁定的'b: 'a ('b outlives'a),然后就可以了

impl<'a, 'b: 'a, T> PartialEq<RefEquality<'b, T>> for RefEquality<'a, T> {
    fn eq(&self, other: &RefEquality<'a, T>) -> bool {
        panic!()
    }
}

該特征需要一個類型的函數:

fn(&RefEquality<'a, T>, &RefEquality<'b, T>)

您提供類型的功能:

fn(&RefEquality<'a, T>, &RefEquality<'a, T>)

我認為,如果'b outlives'a,它們是兼容的似乎是合乎邏輯的,但讓我們冷靜地看待它。

讓我們刪除常數因素:

該特征需要一個類型的函數:

fn(Ref<'b>)

您提供類型的功能:

fn(Ref<'a>)

我們還有where 'b: 'a 我們怎么能看到它們兼容?

子類型II:方差的攻擊

子類型:使用X代替Y是否安全?

方差: 如果 XY的子類型,那么Foo<X>Foo<Y>呢?

另見WikipediaRustonomicon on variance。

生命周期的子類型定義是:

'x <: 'y表示'x長於'y

讓我們練習使用引用的子類型和方差。

什么時候使用&'x i32而不是&'y i32是否&'y i32

'x'y更長壽時,那么更換是安全的。 'x生命長於'y意味着&'x i32&'y i32的子類型:

'x <: 'y => &'x i32 <: &'y i32

子類型關系在同一方向傳播,這稱為協方差 ; &'a i32'a參數中是協變的。

相反,函數的方差行為是這樣的:

X <: Y => fn(Y) <: fn(X)

函數的行為方式與其參數類型相反。 這是逆轉 ,邏輯上“反對”,因為它是相反的方向。

計算

對於這個問題,我們假設Ref<'a>行為就好像它包含一個&'a引用,並且它&'a本身具有相同的方差

我們被賦予了where 'b: 'a的界限,這意味着:

'b <: 'a

使用協方差規則進行參考和參考:

'b <: 'a => Ref<'b> <: Ref<'a>

對函數使用逆變規則**

Ref<'b> <: Ref<'a> => fn(Ref<'a>) <: fn(Ref<'b>)

這就是rustc問的問題, impl函數是特質函數的一個子類型。 它是!

** wrt函數參數

如果我希望生命時間平等怎么辦?

如果你的目標只是為相同的終生案例定義PartialEq ,那么是的, PartialEq lifetime case就可以了。 它在impl中提供了更通用的功能,但類型檢查器確定它是兼容的。

您還可以根據生命周期參數更改RefEquality類型的方差。

如果你想要一個RefEquality<'a, T>只是與完全相同的生命周期兼容的子類型,那就叫做不變性

你可以使用一個具有不變性的原語, std::cell::Cell<T> Cell<T>T參數中是不變的。

完成此操作的常用方法是PhantomData成員:

struct RefEquality<'a, T: 'a> {
    ptr: &'a T,
    marker: PhantomData<Cell<&'a ()>>,
}

如果你想看到一個不變量的應用,請查看crossbeam crate以及'a參數中不變量的Scope<'a>其安全范圍線程的特殊借用規則的基石。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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