2016-04-28 10 views
2

Ich möchte ein Array von 10 leere Vektoren in Rust erstellen, aber [Vec::new(); 10] funktioniert nicht, da VecCopy nicht implementiert. Wie kann ich das tun, und allgemein gesagt, wie kann ich ein Array durch wiederholtes Aufrufen einer Funktion initialisieren?Wie kann ich ein Array mit einer Funktion initialisieren?

+1

Können Sie uns zeigen, was Sie versucht haben? Es sollte kein Problem geben, ein Array aus einer Funktion oder einem Vektor zurückzugeben. Welchen hast du probiert und wie? (Ihr Titel sagt Array, Ihre Frage sagt Vektor). –

+0

Whoops, Sie haben Recht - das ist ein Tippfehler – user3519580

+0

Verwandt: [Warum wird die Eigenschaft Kopieren für die Standardinitialisierung (struct valued) benötigt?] (Http://stackoverflow.com/q/27876588/155423) und [Was ist der richtige Weg, um ein Array fester Länge zu initialisieren?] (http://StackOverflow.com/q/31360993/155423). Duplizieren von [Initialisiere ein großes Array fester Größe mit nicht kopierbaren Typen] (http://stackoverflow.com/q/28656387/155423). – Shepmaster

Antwort

2

Das ist wirklich eine interessante Frage.

Die einzige sichere Lösung, die ich denken kann, ist ein Makro wie dieser

Ich sehe zwei mögliche Ansätze

Erste

Eine einfache Lösung Makro

macro_rules! array { 
    ($v: expr; 1) => ([$v]); 
    ($v: expr; 2) => ([$v, $v]); 
    ($v: expr; 3) => ([$v, $v, $v]); 
    ($v: expr; 4) => ([$v, $v, $v, $v]); 
    ($v: expr; 5) => ([$v, $v, $v, $v, $v]); 
    // until 32 
} 

let a = array![Vec::new(); 3]; 

Es ist ein bisschen ausführlich, aber auch die standard lib verwenden diese Art von Konstrukt.

Zweite

Nach einem Zusammenhang zwischen dieser Frage zu realisieren und other, die ich vorher geantwortet hatte, ich diese Lösung nodrop

extern crate nodrop; 

macro_rules! array { 
    ($e: expr; $n:expr) => (
     { 
      use std::mem; 
      use std::ptr; 
      use nodrop::NoDrop; 

      struct ArrayBuilder<T> { 
       len: usize, 
       data: *mut T, 
      } 

      impl<T> Drop for ArrayBuilder<T> { 
       fn drop(&mut self) { 
        unsafe { 
         while self.len > 0 { 
          let offset = (self.len as isize) - 1; 
          self.len -= 1; 
          ptr::drop_in_place(self.data.offset(offset)); 
         } 
        } 
       } 
      } 

      let mut v: NoDrop<[_; $n]> = NoDrop::new(unsafe { 
       mem::uninitialized() 
      }); 
      // helps type inference for v 
      if false { v[0] = $e; } 
      let mut builder = ArrayBuilder { 
       len: 0, 
       data: (&mut *v as *mut _) as *mut _ 
      }; 
      unsafe { 
       for i in 0..$n { 
        ptr::write(builder.data.offset(i as isize), $e); 
        builder.len = i + 1; 
       } 
      } 
      builder.len = 0; 
      v.into_inner() 
     } 
    ) 
} 

let a = array![Vec::new(); 3]; 

Und einen Test, die zeigt mit schrieb, dass es nicht Leckspeicher

#[test] 
fn test() { 
    static mut COUNT: usize = 0; 

    #[derive(Debug)] 
    struct X(usize); 

    impl Drop for X { 
     fn drop(&mut self) { 
      println!("drop {:?}", self.0); 
     } 
    } 

    impl X { 
     fn new() -> X { 
      unsafe { 
       if COUNT == 3 { 
        panic!(); 
       } 
       let x = X(COUNT); 
       COUNT += 1; 
       x 
      } 
     } 
    } 

    array![X::new(); 6]; 
} 

Bei diesem Test gerät die Methode X::new in Panik, wenn X(3) erstellt wird, also müssen X(0), X(1), X(2) gelöscht werden.

Andere

Es ist eine unsichere Lösung here.

+0

Wäre es theoretisch möglich, ein Makro zu erstellen, das ein solches Konstrukt für jedes n erzeugen kann? Meine eigenen Versuche wurden durch die Regel der Rostmakros behindert, die sich zu einem einzigen Ausdruck ausweiten, was es schwierig macht, eine variable Anzahl von Ausdrücken innerhalb der eckigen Klammern zu haben. – user3519580

+0

Mit dem aktuellen Makro-System ist es nicht möglich. – malbarbo

Verwandte Themen