我是 Rust 的新手,我在泛型函式中有一個奇怪的行為以及一些關于它的問題。我理解結果,但我不知道它是否正常:
trait A {
fn a() {
println!("Oh Noooo...");
}
fn b();
}
struct SA {}
impl SA {
fn a() {
println!("sa");
}
fn b() {
println!("b");
}
}
impl A for SA {
fn b() {
println!("b2");
}
}
fn foo<T>() where T: A {
T::a();
// <T as T>::a(); // -> Generate an error a not in T
}
fn bar<T>() where T: A {
T::b();
// <T as T>::b(); // -> Generate an error b not in T
}
fn main() {
//<SA as SA>::a(); // -> Generate an error not found in SA
SA::a();
foo::<SA>();
SA::b();
bar::<SA>();
}
sa
Oh Noooo...
b
b2
鏈接到操場
我的問題是關于"Oh Noooo ..."。我知道代碼不是常規的,函式a()不在,impl A for SA但是為什么,在泛型函式中,不是a()在SA哪個被呼叫的?我認為該where子句只是對我的結構實作特征這一事實的約束。看起來好像T是在 a 中轉換dyn A,是這樣嗎?
當我想在約束確保存在時強制呼叫<T as T>時,為什么會出現錯誤?wherea
我的問題是在一個更復雜的情況下,該函式a()是由我的塊中的函式上的屬性宏生成的impl SA,我不知道如何在impl塊外生成函式以及是否可能。是為整個impl塊實作我的宏的唯一解決方案嗎?
uj5u.com熱心網友回復:
我知道代碼不是傳統的,函式 a 不在,
impl A for SA但為什么在通用函式中,它不是呼叫 SA 中的 a。
泛型函式 ( ) 中名稱的決議foo不是基于呼叫函式的具體型別,而是基于定義中的型別和特征。當編譯器處理
fn foo<T>() where T: A {
T::a();
}
它用來查找的唯一a資訊是T實作. 因此,它等效于or ,呼叫 trait 方法。TAA::a()<T as A>::a()
這不僅僅是一個隨意的選擇,而是 Rust 設計的一個重要部分——一個泛型函式的作業方式完全相同,而不管任何命名沖突或與它一起使用的型別的其他附帶細節。要了解如果 Rust 作業方式不同,我們會如何得到錯誤,請考慮以下程式:
trait A {
fn a(x: i32);
}
struct SA {}
impl SA {
fn a(x: &str) {}
}
fn foo<T>() where T: A {
T::a("hello world");
}
trait 函式A::a需要一個&str,但固有函式SA::a需要一個i32。如果名稱決議決定應該選擇可用的固有函式,那么foo::<SA>()即使泛型函式定義本身是可以的,也會出現型別錯誤。這很糟糕,因為這意味著泛型函式可能會因為型別具有某個關聯的函式名稱而失敗。而且,這將是一個“單態化后錯誤”——除非在每次使用它的背景關系中,否則無法知道泛型函式的定義是有效的(型別檢查等)。這會產生難以除錯的問題,并且還會減慢編譯速度,因為需要進行更多檢查。
為避免此問題,您應該將固有關聯函式視為本質上與 trait 關聯函式位于不同的命名空間中。您不能簡單地通過給它一個匹配的名稱來從泛型函式呼叫固有函式——泛型函式只呼叫特征函式(當涉及型別變數時;當然,泛型函式可以呼叫關聯型別的固有函式)。
我認為 where 只是對我的結構實作特征這一事實的限制。
是的,但問題是您的泛型函式將永遠無法呼叫固有函式,SA::a()除非它明確提到該具體型別。并不是該where子句是hidden SA::a(),而是根本不可能與該子句SA::a() 相關T。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/510448.html
標籤:仿制药锈性状
上一篇:帶有通用型別欄位的Lombok的@Builder錯誤
下一篇:將多種方法重構為一個通用方法
