2016-08-22 21 views
2

Ich versuche, eine Schließung von einem methoddo_something für Struktur A implementiert aufrufen. Ich habe ein paar Posts darüber gelesen, aber ich bin jetzt ein wenig verloren. Hier ist eine vereinfachte Version:So rufen Sie eine Schließung in einer Methode

// A simple structure 
struct A<F> { 
    f: F, 
} 

// Implements new and do_something 
impl<F> A<F> where F: Fn() { 
    fn new(f: F) -> A<F> { 
     A { f: f } 
    } 
    fn do_something(&self) { 
     self.f() // Error is here. 
    } 
} 

fn main() { 
    let a = A::new(|| println!("Test")); 
    a.do_something() 
} 

Es zeigt diesen Fehler:

error: no method named f found for type &A<F> in the current scope

Ich dachte Verschlüsse just like this genannt wurden, aber es scheint, dass ich etwas verpasst. Ich habe versucht (ohne wirklich zu verstehen Zufallstest) self.f() mit self.f.call() zu ersetzen, aber es sagt, zwei Sache:

  1. error: this function takes 1 parameter but 0 parameters were supplied
  2. error: explicit use of unboxed closure method call is experimental [E0174]

ich über den ersten Fehler bin nicht sicher, aber ich denke, ich werde nicht über diese Funktion nun verwenden, wenn es Experimental.

Gibt es eine Möglichkeit, eine Schließung in einer Methode aufzurufen?

Antwort

4

Wickeln Sie den Mitgliedsnamen in Klammern:

fn do_something(&self) { 
    (self.f)() 
} 

Wenn ich die zugrunde liegende Ursache mit Vorrang zu tun hat, richtig erinnere, wenn Sie den Code Parsen. self.f() sucht nach einer Methode mit dem Titel f und schlägt fehl, weil sie nicht existiert. (self.f)() bewirkt, dass es anders geparst wird, insbesondere nach einer Elementvariablen.

2

Der zweite Fehler ist hier ein Problem, unboxed Verschlüsse sind ein Schmerz zu behandeln. Sie müssenkönnte Box die Schließung (legen Sie es hinter einem Zeiger), weil Verschlüsse alle Arten von seltsamen Größen haben können.

EDIT: Wie Shepmaster darauf hinwies, dies teilweise falsch. Ich werde die alte Antwort weiter unten ausdehnen, weil es beim Umgang mit Schließungen und deren Weitergabe hilfreich sein könnte.

(Auch ist call experimentell und nicht notwendig in diesem Fall, so machen wir es ohne das tun)

struct A<F> { 
    f: Box<F>, 
} 

Jetzt, wo es in einem Box (Heap zugewiesenen Speicher gespeichert ist, aber Sie können auch andere verwenden Arten Indirekt wenn notwendig), sollten Sie auch die Struktur richtig initialisiert werden:

fn new(f: F) -> A<F> { 
    A { 
     f: Box::new(f) 
    } 
} 

Schließlich können Sie es nennen, nicht wahr?

Aber der Rust-Compiler will hier noch eine Methode statt unseres Closure-Feldes nennen. So dereferenzieren wir explizit die Box:

fn do_something(&self) { 
    (*self.f)() // Explain our intentions to the confused compiler 
} 

Und jetzt, es funktioniert! Aber brauchen wir hier die Indirektion? Ich dachte es, aber es scheint nicht (danke Shep)! Sie sehen, die A Struktur ist bereits generisch, so sollte es eine Größe haben, die für jeden einzelnen F Typ geeignet ist.So brauchen wir nicht den Indirektionsoperator, und die alte Definition verwenden:

struct A<F> { 
    f: F, 
} 

Aber jetzt haben wir zumindest bekam einen Hinweis darauf, was hier passiert, und do_something kann

fn do_something(&self) { 
    (self.f)() // Explicitly access a struct member, then call it 
} 
zu

reduziert werden

Es scheint also nur eine syntaktische Einschränkung des Rust-Compilers hinsichtlich der Aufrufsyntax zu sein.

+1

Es ist nicht ich:/Danke trotzdem! –

+1

Der Hauptpunkt über Schließungen mit seltsamen Größen ist genau, aber der Compiler kennt die Größe von Schließungen und es ist möglich, das Boxen zu vermeiden. Sie müssen die Box auch nicht explizit dereferenzieren, um sie aufzurufen - "Box" implementiert "Deref". Daher funktioniert '(self.f)()' genauso gut, wenn es in einem Rahmen ist. – Shepmaster

Verwandte Themen