Impossible de placer le type non dimensionné avec une syntaxe complète [duplicate]
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
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é.