trait Trait {
fn p(self);
}
impl<T> Trait for fn(T) {
fn p(self) {
print!("1");
}
}
impl<T> Trait for fn(&T) {
fn p(self) {
print!("2");
}
}
fn f(_: u8) {}
fn g(_: &u8) {}
fn main() {
let a: fn(_) = f;
let b: fn(_) = g;
let c: fn(&_) = g;
a.p();
b.p();
c.p();
}
HRTBs
有點相像,但是不是。
這裡順便解釋一下:獨屬於自身的方法宣告繫結。where for<'a> F: Fn(&'a (u8, u16)) -> &'a u8
一般在方法的內部,如果需要生命週期引數,都可以直接宣告。
但是對於Fn
,有時候時候呼叫是不確定的。
它的呼叫完全可以獨立於物件之外,只在乎方法入參和出參,以及內部操作。
這個時候使用for
進行單獨的宣告週期繫結就可以達到該目的。T
泛型T
的意思,可不僅僅是針對擁有所有權的物件,而是Object
。
引用,本身也是一種物件,毫不客氣的說, \&T \in T。
這道題裡面都為fn
實現了Trait
,當然,這並不是HRTBs
。
如果是fn(T)
的簽名,會列印1
。
如果是fn(&T)
的簽名,會列印2
。
後續透過匹配的方式,讓編譯器自動的推導對應的宣告型別,從而觸發列印。
很明顯能看出來
f
的引數型別是u8
g
的引數型別是&u8
這裡主要看的就是如何匹配的泛型了。
let a: fn(_) = f;
這個毫無疑問,匹配的_
推匯出來必然是T
。
這裡T = u8
, 因此列印1
。let b: fn(_) = g;
這是比較讓人犯迷糊的,因為g
的入參是&u8
。
但是,對於b
而言,匹配方式是_
,只要有入參,它就匹配,就是T
。
這裡T = &u8
,因此列印1
。let c: fn(&_) = g;
這裡可以看到,這個匹配模式是&_
,對應匹配的是&u8
。
這裡的_
提取出來的是T=u8
,但是作為整體而言,也就是&T
。
也就是說,這裡強制表達的是,入參必須是一個引用。
當明確入參是一個引用的時候,就會列印2
。
因此結果不言而喻112
。
這裡的匹配和其他的匹配不太一樣,它是經過推導之後在進行的匹配。
儘管我們的Trait
實現中已經標明瞭泛型型別,但是最終還需要匹配函式簽名。
作為一個整體進行解析,最重要的就是宣告的準確性,不能過於依賴編譯器的自動推理。
沒有明確的指定,\&T \in T可能會出現預料之外的情況。
本作品採用《CC 協議》,轉載必須註明作者和本文連結