繁体   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