2017-08-10 3 views
0

Ich versuche, einige Abschnitte meines Codes leichter zu lesen, indem Sie kleine Helfer-Schließungen verwenden.Kann nicht einer Variablen zugewiesen werden, die in einer Schließung verwendet wird, weil es geliehen ist

fn main() { 
    let mut loop_index = 0; 

    let get_src_index = || return loop_index % 2; 
    let get_dst_index = || return (loop_index + 1) % 2; 

    loop_index += 1; 
} 

Es gibt noch ein paar Verschlüsse, die Verwendung von get_src_index() und get_dst_index(), aber sie sind nicht wichtig, um das Problem zu machen. Das Problem ist, dass ich nicht mehr loop_index ändern kann:

error[E0506]: cannot assign to `loop_index` because it is borrowed 
--> src/main.rs:6:5 
    | 
4 |  let get_src_index = || return loop_index % 2; 
    |       -- borrow of `loop_index` occurs here 
5 |  let get_dst_index = || return (loop_index + 1) % 2; 
6 |  loop_index += 1; 
    |  ^^^^^^^^^^^^^^^ assignment to borrowed `loop_index` occurs here 

Ich verstehe nicht ganz, warum Rust nicht die loop_index Variable erhöht wird nicht gestattet. Gibt es einen "rostigen" Weg, dies zu tun?

+1

Die Nachricht des Compilers scheint nicht mit dem obigen Code übereinzustimmen. Bitte mach einen MCVE, vorzugsweise mit einem Link zum [Rust Playground] (https://play.rust-lang.org/). –

+0

@ E_net4 das hat mich auch erwischt. OP teilte den Code in zwei Blöcke auf, aber es war die Kombination der beiden, die den Fehler hatten. – Shepmaster

Antwort

4

Wie die Fehlermeldung besagt, können Sie den Wert nicht ändern, da er ausgeliehen ist. Es ist das gleiche, als wenn Sie hatte gesagt:

let mut loop_index = 0; 
let foo = &loop_index; 
loop_index += 1; 

Sie nicht zu modify a value while there is an outstanding immutable borrow erlaubt sind. Dies ist ein grundlegendes Konzept in Rust und unterstreicht die Sicherheit, die es bietet.

Warum hat die Schließung einen Verweis auf die Variable? Das ist der gesamte Punkt von Verschlüsse - zu capture the environment. Verschlüsse folgern, wie die Variablen basierend auf den Operationen, die innerhalb stattfinden, erfasst werden, und in diesem Fall ist eine Referenz ausreichend.

Dies ist normalerweise das, was Sie wollen, weil eine Referenz leicht zu umgehen ist. In dieser Fall haben Sie Nummern, so gibt es keinen Grund, die Referenz zu bevorzugen. Wir können das Schlüsselwort move verwenden, um die Nummer in die Schließung zu verschieben. Da Zahlen Copy implementieren, wird dies eine Kopie machen. Dann wird der Verschluss vollständig getrennt von dem bestehenden Wert:

let mut loop_index = 0; 

let get_src_index = move || loop_index % 2; // No need for `return` 
let get_dst_index = move || (loop_index + 1) % 2; 

loop_index += 1; 

Aber ich glaube nicht, dass diese speziellen Schließungen wirklich kaufen Sie nichts. Integer-Operationen sind in der Regel billig und die Bedingungen sind oft weniger günstig, so dass eine zusätzliche Berechnung besser sein könnte.


Wenn Sie die Fähigkeit erforderlich, um die loop_index zu ändern und diese Änderung innerhalb der Verschlüsse reflektiert haben, könnten Sie eine Cell verwenden:

use std::cell::Cell; 

fn main() { 
    let mut loop_index = Cell::new(0); 

    let get_src_index = || loop_index.get() % 2; 
    let get_dst_index = || (loop_index.get() + 1) % 2; 

    loop_index.set(loop_index.get() + 1); 
} 

Auch besser, Sie in vielen Fällen Sie müssen Ihren eigenen Schleifenindex ohnehin nicht pflegen. Iterator::enumerate kümmert sich darum für Sie.

+0

Vielen Dank für diese Erklärung. Ich denke nicht, dass ich 'enumerate()' hier verwenden kann, die Verwendung der 'Cell' funktioniert jedoch völlig in Ordnung! :) –

Verwandte Themen