Impossibile inscatolare tipi non dimensionati con sintassi completa [duplicato]
Ho provato a inscatolare una chiusura utilizzando la sintassi completa:
let x = Box::<SomeType>::new(some_value);
e si aspettava che funzionasse esattamente allo stesso modo di:
let x: Box<SomeType> = Box::new(some_value);
cioè: compilare.
Invece, ho ricevuto un errore del compilatore che dice che il metodo new
non può essere chiamato Box
con un parametro di tipo non dimensionato:
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`
Penso che questo potrebbe essere causato dai metodi di impl
of Box
dichiarati come
impl<T> Box<T> {
...
}
e quindi richiedono implicitamente che il parametro type sia Sized
, ma se è così, perché è dichiarato in questo modo e perché la chiamata funziona quando non è qualificata?
Risposte
Questo in effetti accade a causa del modo in cui viene dichiarato Box
's impl
, ma se ci pensi, ha senso: il new
metodo prende un valore che è in pila, e quindi deve esserlo Sized
.
perché la chiamata funziona quando non è qualificata?
Questo spesso (ma non sempre) funziona, perché il tipo che stai fornendo alla new
funzione non è in realtà non dimensionato: viene ampliato solo a un tipo non dimensionato una volta assegnato a una variabile con un tipo più generale.
Riutilizziamo l'esempio che hai usato e scopriamo perché la seconda versione che hai pubblicato funziona:
let boxed: Box<dyn FnMut() -> i32> = Box::new(|| 0);
Il riferimento ruggine afferma :
Un'espressione di chiusura produce un valore di chiusura con un tipo univoco e anonimo che non può essere scritto. Un tipo di chiusura è approssimativamente equivalente a una struttura che contiene le variabili catturate.
Ciò significa che il tipo di chiusura a cui si passa new
non è effettivamente dyn FnMut() -> i32
, ma piuttosto un tipo unico di quella specifica chiusura, che non può essere scritta in alcun modo, e quindi deve essere dedotto.
Il riferimento nota anche in seguito :
Implementano tutti i tipi di chiusura
Sized
.
Quindi, in effetti, il tipo è sempre stato ridimensionato, è solo che l'assegnazione successiva a una variabile di tipo dyn FnMut() -> i32
ha ampliato il tipo di chiusura originale a uno più generale, non dimensionato.