簡體   English   中英

為 dyn Fns 實現特征

[英]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);
    }
}

您會收到一條錯誤消息,指出類型參數不受約束。 錯誤1

我明白了,不相信用 generics 可以做到這一點。 但是動態方法,為什么不起作用? 它給出了以下錯誤:

錯誤2

我不明白這個錯誤。 它聲明我通過了一個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.

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