Impossible de placer le type non dimensionné avec une syntaxe complète [duplicate]

Aug 24 2020

J'ai essayé de boxer une fermeture en utilisant la syntaxe complète:

let x = Box::<SomeType>::new(some_value);

et je m'attendais à ce que cela fonctionne exactement de la même manière que:

let x: Box<SomeType> = Box::new(some_value);

ie: compiler.

Au lieu de cela, j'ai eu une erreur de compilation disant que la méthode newne peut pas être appelée Boxavec le paramètre de type unsized:

error[E0599]: no function or associated item named `new` found for struct `std::boxed::Box<dyn std::ops::FnMut() -> i32>` in the current scope
   --> src/bin/observable_test/mod.rs:57:40
    |
57  |     let boxed = Box::<dyn FnMut() -> i32>::new(|| 0);
    |                                           ^^^ function or associated item not found in `std::boxed::Box<dyn std::ops::FnMut() -> i32>`
    | 
   ::: /mnt/data/william stanley/applications/rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ops/function.rs:151:1
    |
151 | pub trait FnMut<Args>: FnOnce<Args> {
    | ----------------------------------- doesn't satisfy `dyn std::ops::FnMut() -> i32: std::marker::Sized`
    |
    = note: the method `new` exists but the following trait bounds were not satisfied:
            `dyn std::ops::FnMut() -> i32: std::marker::Sized`

Je pense que cela pourrait être causé par la impldes Boxméthodes de » être déclarées

impl<T> Box<T> {
    ...
}

et donc implicitement exiger que le paramètre type soit Sized, mais si tel est le cas, pourquoi est-il déclaré de cette manière, et pourquoi l'appel fonctionne-t-il quand il n'est pas qualifié?

Réponses

1 WilliamStanley Aug 24 2020 at 01:33

Cela se produit en effet à cause de la façon dont le Box's implest déclaré, mais si vous y réfléchissez, cela a du sens: la newméthode prend une valeur qui est sur la pile, et donc elle doit l'être Sized.

pourquoi l'appel fonctionne-t-il s'il n'est pas qualifié?

Cela fonctionne souvent (mais pas toujours), car le type que vous fournissez à la newfonction n'est en fait pas non dimensionné - il n'est élargi à un type non dimensionné qu'une fois qu'il est affecté à une variable de type plus général.

Réutilisons l'exemple que vous avez utilisé et découvrons pourquoi la deuxième version que vous avez publiée fonctionne:

let boxed: Box<dyn FnMut() -> i32> = Box::new(|| 0);

La référence de la rouille indique :

Une expression de fermeture produit une valeur de fermeture avec un type anonyme unique qui ne peut pas être écrit. Un type de fermeture équivaut à peu près à une structure qui contient les variables capturées.

Cela signifie que le type de fermeture transmis newn'est pas en fait dyn FnMut() -> i32, mais plutôt un type unique de la fermeture spécifique, qui ne peut en aucun cas être écrit et doit donc être déduit.

La référence note également plus tard :

Tous les types de fermeture sont mis en œuvre Sized.

Donc, en effet, le type a toujours été dimensionné, c'est juste que l'affectation ultérieure à une variable de type dyn FnMut() -> i32a élargi le type de fermeture d'origine à un type plus général, non dimensionné.