2017-11-20 1 views
0

ich einige Code in Rust Schreiben für die ersten 500 Zahlen in der Collatz Folge von 46445645645564584. ErzeugungWarum verhindert das Ausleihen das Einreihen eines Funktionsaufrufs in den Arrayzugriff?

use std::fmt::Debug; 

//Calculate the first 500 numbers in the Collatz sequence of 46445645645564584 

fn main() { 
    let mut v = vec![46445645645564584]; 

    for _ in 0..500 { 
     let last = v[v.len() - 1]; 
     v.push(next(last)); 
    } 

    print_array(&v); 
} 

fn next(n: i64) -> i64 { 
    if n % 2 == 0 { 
     n/2 
    } else { 
     3 * n + 1 
    } 
} 

fn print_array<T: Debug>(v: &[T]) { 
    for x in v { 
     println!("{:?}", x); 
    } 
} 

Dies funktioniert, aber ich möchte die Variable last inline:

for _ in 0..500 { 
    v.push(next(v[v.len() - 1])); 
} 

In Meine Augen, das sollte die Semantik des Programms nicht ändern, da ich einfach eine Variable inline eingezeichnet habe. Allerdings gibt den Rust Compiler die folgenden Fehler, wenn ich versuche, dies zu kompilieren:

error[E0502]: cannot borrow `v` as immutable because it is also borrowed as mutable 
--> src/main.rs:9:21 
    | 
9 |   v.push(next(v[v.len() - 1])); 
    |   -   ^   - mutable borrow ends here 
    |   |   | 
    |   |   immutable borrow occurs here 
    |   mutable borrow occurs here 

error[E0502]: cannot borrow `v` as immutable because it is also borrowed as mutable 
--> src/main.rs:9:23 
    | 
9 |   v.push(next(v[v.len() - 1])); 
    |   -   ^   - mutable borrow ends here 
    |   |    | 
    |   |    immutable borrow occurs here 
    |   mutable borrow occurs here 

Wie ich es sehe, die unveränderlich borrow von v sollte fallen gelassen recht, wenn der Wert v[v.len() - 1] berechnet wird und auf next() weitergegeben. Das bedeutet, dass der veränderbare Kredit von v im äußersten Call zu v.push() erfolgreich sein würde, da der vorherige Borgen gelöscht wurde. Sehe ich das falsch? Oder ist das ein Compiler Bug?

Ich bin mir bewusst, dass Sie dies auch mit Iteratoren/Generatoren tun könnten, aber ich würde gerne wissen, warum dies in diesem bestimmten Code geschieht, da dies ein Problem sein könnte, auf das ich irgendwann noch einmal zurückkommen werde .

Antwort

0

Während Sie Recht haben, dass es im Prinzip möglich wäre, die Leistung von Rust's Border Checker zu erweitern, um die von Ihnen durchgeführte Analyse durchführen zu können, ist der Borg-Checker derzeit nicht in der Lage zu dieser Art von Argumentation.

Wie Sie in dem Fehler sehen können, den Sie erhalten, v.push leiht v aus, und danach wird der Ausdruck next(v[v.len() - 1]) analysiert; aber v ist bereits geliehen von v.push, so dass der Border-Checker fehlschlägt.

Die Border Checker kann knifflig sein, und natürlich kann es verbessert werden, aber ab sofort ist dies das erwartete Verhalten für die Border Checker, und die Lösung ist nur die Indizierung Operation von der Push-Operation trennen, wie Sie ursprünglich tat. Der Compiler ist schlau genug, um die Operation (nachdem alle Borrow-Checks durchgeführt wurden) trotzdem zu inline zu schreiben.

+0

Das Problem sollte eigentlich behoben werden, sobald [non-lexikalische Lebenszeiten] (http://smallcultfollowing.com/babysteps/blog/2016/04/27/non-lexical-lifetimes-in-troduction/) es in die machen stabiler Compiler. – user4815162342

Verwandte Themen