簡體   English   中英

`Box` 是否掩蓋了特征界限? 在這種情況下,為什么我可以將 `dyn FnOnce()` 分配給 `dyn Fn()`?

[英]Does `Box` obscure trait bounds? Why can i assign `dyn FnOnce()` to `dyn Fn()` in this case?

我想要一個結構Quox ,它可以有選擇地擁有周圍可能存在的每種類型的閉包( FnFnMutFnOnce )。 我是這樣輸入的:

#[derive(Default, Debug)]
pub struct Quox<Tfn: Fn(&Person) + Sized, Tfnmut: FnMut(&mut Person) + Sized, Tfnonce: FnOnce(&Person) + Sized> {
    soft_closure: Option<Tfn>,
    mut_closure : Option<Tfnmut>,
    move_closure: Option<Tfnonce>,
}

現在,當我通過Box實例化它時,因為 Rust 抱怨the trait Sized is not implemented for `dyn Fn()`rustcE0277 (也許有更好的方法或者我誤解了特征對象?):

pub fn main(){
    let mut qx = Quox::<Box<dyn Fn(&Person)>, Box<dyn FnMut(&mut Person)>, Box<dyn FnOnce(&Person)>> {
        move_closure: None,
        mut_closure : None,
        soft_closure: None,
    };
    ...

}

  1. 真正讓我感到困惑的是,當我創建相應類型的閉包時——為什么我可以隨意地將它們分配給qx中的字段:

pub fn main(){
    let mut qx = Quox::<Box<dyn Fn(&Person)>, Box<dyn FnMut(&mut Person)>, Box<dyn FnOnce(&Person)>> {
        move_closure: None,
        mut_closure : None,
        soft_closure: None,
    };


    let greeting  = "Hi. We are moving soon!".to_string();
    let clsr_move = move |p:&Person| println!("Hi, {}. {} says: {}", p.name, p.name, greeting);
    let only_a_ref_clsr = |p:&Person| println!("Hi, {}.",p.name );

 
    // qx.move_closure = Some(Box::new(clsr_move));        // expected
    // qx.soft_closure = Some(Box::new(only_a_ref_clsr));  // expected

    qx.soft_closure = Some(Box::new(clsr_move));           // Why is this valid???
    qx.move_closure = Some(Box::new(only_a_ref_clsr));     // Ok Fn is supertrait to FnOnce

}

同樣,令人困惑的是,我在嘗試將(看似) FnMut分配給Fn時沒有收到任何錯誤。


  1. 此外...為什么現在將Box分配給中間變量會引發錯誤???

pub fn main(){
    let mut qx = Quox::<Box<dyn Fn(&Person)>, Box<dyn FnMut(&mut Person)>, Box<dyn FnOnce(&Person)>> {
        move_closure: None,
        mut_closure : None,
        soft_closure: None,
    };


    let greeting  = "Hi. We are moving soon!".to_string();
    let clsr_move = move |p:&Person| println!("Hi, {}. {} says: {}", p.name, p.name, greeting);
    let only_a_ref_clsr = |p:&Person| println!("Hi, {}.",p.name );

    let someboxmove = Some(Box::new(only_a_ref_clsr));
    qx.soft_closure = someboxmove;                         // Invalid. 

}

我得到的錯誤是:

let someboxmove: Option<Box<|&Person| -> ()>>
Go to Option | Box | Person | Global

mismatched types
expected enum `Option<Box<dyn for<'r> Fn(&'r traitobjects::Person)>>`
   found enum `Option<Box<[closure@src/traitobjects.rs:49:27: 49:66]>>`rustcE0308
traitobjects.rs(49, 27): the found closure
traitobjects.rs(66, 5): expected due to the type of this binding

歸結你的第一個問題:

let greeting  = "Hi. We are moving soon!".to_string();
let clsr_move = move |p:&Person| println!("Hi, {}. {} says: {}", p.name, p.name, greeting);

let soft_closure: Box<dyn Fn(&Person)> = Some(Box::new(clsr_move));

clsr_move沒有理由不能是Fn move是為了告訴編譯器將所有捕獲移動閉包中,但是嚴格FnOnce的閉包是變量是否被移出閉包。 這個閉包顯然可以被一次又一次地調用。


你的第二個問題只是 Rust 類型推斷的副作用。 如果Box::new()應該創建的類型不能立即從表達式中明確,那么它將選擇給它的類型; 在后一種情況下,閉包的匿名類型。 在前者中,它可以看到它將被分配給期望Box<dyn...>的東西並且可以搶先強制類型。 所以很簡單,推理算法看得不夠遠。

它也不能隱式地將Option<Box<T>>強制轉換為Option<Box<dyn Trait>> 它可以將Box<T>強制轉換為Box<dyn Trait> ,但由於它們具有不同的大小和布局,因此它不會擴展為Option的通用參數

暫無
暫無

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

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