2017-03-31 1 views
0

ich ein einfaches Spiel in Rust ich schreibe, die eine Drawer enthält, die einmal aufgebaut ist, und dann als änderbare Referenz durch viele Methoden übergeben:eine Struktur Mit einem geliehenen Parameter enthält

pub struct Drawer<'a> { 
    // ... 
    renderer: Renderer<'a>, 
    // ... 
} 

fn pause(drawer: &mut Drawer, events: &[Event]) { 
    // ... 
    drawer.draw_text(&TextPos::Centered, "Paused", 1); 
    // ... 
} 

ich wollte Refactoring meinen Code eine fließend Schnittstelle zum zeichnen von Text, wie einzuführen:

drawer.text() 
    .size(4) 
    .centered() 
    .draw("Paused"); 

ich das tat eine TextDrawer Struktur durch die Schaffung, das enthält einen Verweis auf die Drawer:

pub struct TextDrawer<'a, 'b: 'a> { 
    pos: TextPos, 
    size: u32, 
    drawer: &'a mut Drawer<'b>, 
} 

impl<'a> Drawer<'a> { 
    pub fn text(&mut self) -> TextDrawer { 
     TextDrawer { 
      pos: TextPos::At(0, 0), 
      size: 1, 
      drawer: self, 
     } 
    } 
} 

Ich denke, die Lebenszeiten, die ich auf der Struktur gesetzt habe, sind korrekt (die Referenz muss so lange dauern wie die selbst).

Allerdings wird meine text Methode nicht kompilieren, bis ich explizite Lebenszeiten hinzufüge. Wenn ich das tue, verlangt jede Methode, die text aufruft, dann explizite Lebensdauern und so weiter. Ich bin überrascht diese Lebenszeiten zu sagen: Schließlich sind sie alle der Form fn foo<'a, 'b: 'a>(drawer: &mut'a Drawer<'b>). Ich hatte vorher angenommen, dass dies bereits die abgeleitete Lebensdauer war, da es immer notwendig war, dass die Referenz so lange wie die selbst dauerte.

Ist es für mich notwendig, diese expliziten Lebensdauern alle anderen meine Methodensignaturen zu setzen? Oder kann ich es auf andere Weise vermeiden?

+2

Nicht verwandt mit Ihrer Frage, aber Sie könnten in Erwägung ziehen, 'Drawer' in etwas umzuwandeln, das keine gebräuchliche zweite Bedeutung hat. Zumindest unter der Annahme, dass es ausgesprochen werden soll/drɔ ər/statt/dror/ – trentcl

+0

können Sie Ihren Fehler posten? Was Sie gepostet haben, sieht nicht so aus, als würde es kompilieren. Die Rückgabe von TextDrawer deutet möglicherweise auf die falschen Grenzen hin, aber das ist mir nicht klar. Und 'Schublade: & 'ein mut Drawer <'b>' sieht falsch aus, da Sie nicht auf innere Typen reagieren müssen (Mutabilität wird durch den Verweis auf den Typ geerbt, und alles ist veränderbar in dem Typ, wenn ein Verweis darauf ist) . – bluejekyll

+1

@bluejekyll Ihre letzte Aussage ist falsch: Sie können nichts durch ein '& mut & T' (veränderliche Referenz auf eine unveränderliche Referenz) ändern. Also macht die veränderbare Referenz im Inneren Sinn (außer wenn ich etwas Entscheidendes vermisse). –

Antwort

1

Dank der minimal example von Lukas oben, stellte ich fest, dass ich einfach die Lebensdauer Parameter zu meiner text Methode rückwärts bekommen hatte.

Meine falsche Lebensdauer:

impl<'a> Drawer<'a> { 
    pub fn text<'b>(&'b mut self) -> TextDrawer<'a, 'b> { 
     // omitted 
    } 
} 

Die richtigen Leben:

impl<'a> Drawer<'a> { 
    pub fn text<'b>(&'b mut self) -> TextDrawer<'b, 'a> { 
     // omitted 
    } 
} 

Danach kompiliert alles ohne weitere explizite Lebensdauer.

Verwandte Themen