[英]implementing traits for dyn Fns
今天我在玩 function 特征。 盡管我在下面展示的示例實際上可能不是很有用,但我確實想知道為什么它不能編譯。
pub fn do_something(o: &(dyn Other + 'static)) {
}
trait Other {
fn do_something_other(&self);
}
impl<A> Other for dyn Fn(A) {
fn do_something_other(&self) {
do_something(self);
}
}
在這里,我為 function 類型實現了一個特征。 這個 function 類型在它的參數上是通用的。 這意味着如果您要這樣做:
pub fn do_something(o: &(dyn Other + 'static)) {
}
trait Other {
fn do_something_other(&self);
}
impl<F, A> Other for F where F: (Fn(A)) + 'static {
fn do_something_other(&self) {
do_something(self);
}
}
我明白了,不相信用 generics 可以做到這一點。 但是動態方法,為什么不起作用? 它給出了以下錯誤:
我不明白這個錯誤。 它聲明我通過了一個Fn(A) -> ()
,它沒有實現Other
。 但是,此錯誤實際上發生在Other
的實現中。 怎么不能在這里實現呢?
我的第一個想法是因為每個閉包都是它自己的類型。 如果它與此有關,我發現錯誤非常奇怪。
第一個構造失敗,因為您無法將&dyn A
轉換為&dyn B
,即使在為dyn A
實現B
時也是如此。
trait A {}
trait B {
fn do_thing(&self);
}
impl B for dyn A {
fn do_thing(&self) {
let b: &dyn B = self;
}
}
error[E0308]: mismatched types
--> src/lib.rs:9:25
|
9 | let b: &dyn B = self;
| ------ ^^^^ expected trait `B`, found trait `A`
| |
| expected due to this
|
= note: expected reference `&dyn B`
found reference `&(dyn A + 'static)`
好吧,您可以轉換特征,但只能在源特征的幫助下。 但由於在這種情況下源是Fn
,所以這不是一條路線。
第二個構造失敗,因為 Rust 不會讓您實現可能發生沖突的特征。 嘗試為實現A<_>
的類型實現B
將自動被拒絕,因為類型可以具有A<_>
的多個實現。
trait A<T> {}
trait B {
fn do_thing(&self);
}
impl<T, U> B for T where T: A<U> {
fn do_thing(&self) {}
}
error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates
--> src/lib.rs:7:9
|
7 | impl<T, U> B for T where T: A<U> {
| ^ unconstrained type parameter
特別是關於Fn
,它有點難以分辨,因為通常 function 對象僅實現單個Fn
特征。 但是,關鍵字通常是因為您可以在每晚啟用一項功能來做到這一點。 而且特質系統通常不會受到青睞。
所以,你可以做什么? 那么第一種方法仍然是函數式的,只是你必須將實現保持在特征內。 如果您對 function arguments 使用具體類型,則可以使用第二種方法。
您可以想象為&dyn Fn(_)
實現Other
(在參考而不是 object 本身上實現它)。 但這對於通常使用Fn
對象的方式並不是特別方便。
pub fn do_something(o: &dyn Other) {}
trait Other {
fn do_something_other(&self);
}
impl<A> Other for &dyn Fn(A) {
fn do_something_other(&self) {
do_something(self);
}
}
fn main() {
// THIS WORKS
let closure: &dyn Fn(_) = &|x: i32| println!("x: {}", x);
closure.do_something_other();
// THIS DOESN'T WORK
// let closure = |x: i32| println!("x: {}", x);
// closure.do_something_other();
}
另一種選擇是使Other
特征通用以約束A
,但這當然取決於它的設計使用方式。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.