Impossibile inscatolare tipi non dimensionati con sintassi completa [duplicato]

Aug 24 2020

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 newnon può essere chiamato Boxcon 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 implof Boxdichiarati 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

1 WilliamStanley Aug 24 2020 at 01:33

Questo in effetti accade a causa del modo in cui viene dichiarato Box's impl, ma se ci pensi, ha senso: il newmetodo 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 newfunzione 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 newnon è 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() -> i32ha ampliato il tipo di chiusura originale a uno più generale, non dimensionato.