Да, этот момент довольно запутанный, и я думаю, что формулировка книги Rust вносит свой вклад. После прочтения я подумал так же, как и вы: что move
замыкание обязательно FnOnce
и что не move
замыкание FnMut
(а также может быть Fn
). Но это как бы назад от реальной ситуации.
Закрытие может захватывать значения из области, в которой оно создано. move
контролирует, как эти значения попадают в замыкание: путем перемещения или по ссылке. Но то, как они используются после захвата , определяет, является ли закрытие FnMut
или нет.
Если тело затвора использует какое-либо захваченное значение, тогда затвор может быть только FnOnce
. После первого запуска замыкания и использования этого значения оно не может быть запущено снова.
Как вы упомянули, вы можете потреблять значение внутри замыкания, вызывая drop
для него или другими способами, но наиболее распространенный случай - вернуть его из замыкания, что выводит его из замыкания. , Вот самый простой пример:
let s = String::from("hello world");
let my_fnonce = move || { s };
Если тело затвора не потребляет ни одного из его захватов, то это FnMut
, независимо от того, было ли оно move
или нет. Если он также не изменяет ни один из своих снимков, он также Fn
; любое закрытие, равное Fn
, также FnMut
. Вот простой пример, хотя и не очень хороший.
let s = "hello world";
let my_fn = move || { s.length() }
Краткое описание
Модификатор move
контролирует, как захваты перемещаются в замыкание, когда оно создано . FnMut
членство определяется тем, как перехваты перемещаются из закрытия (или используются каким-либо другим способом), когда выполнено .