2017-01-19 3 views
4

Im folgenden Beispiel, in dem der Testabschluss als Funktionsparameter übergeben wird, ist kein @ escaping erforderlich. Bedeutet es, dass es sich um eine Noescape-Schließung handelt? Ich frage mich, ob dies ein Workaround ist, um die durch das Entweichen verursachte Heap-Zuweisung zu vermeiden.Sind bei der Verwendung in generischen typisierten Daten Verschlüsse ausgeblendet?

func test() { 
    print("hello") 
} 

class b<T> { 
    let closure: T 
    // does not requires init(c: @escaping() -> Void) 
    init(c: T) { 
     self.closure = c 
    } 
} 

var c = b(c: test) 
+2

Schließung nicht unbedingt bedeutet asynchrone –

+0

@LeoDabus, was Sie damit meinen Sie? –

+0

Ich glaube nicht, dass Generika irgendwelche Unterschiede machen, zu der Definition von fliehenden und nicht fliehenden Verschlüssen. In Ihrem Beispiel gibt es, soweit ich sehen kann, keine Flucht. – Dasem

Antwort

1

Bedeutet es, es als noescape Schließung zählt?

Ihre generische Version trickt den Compiler.

Der Compiler scheint für alle Methodenargumente zu suchen, die vom Typ Schließung sind und innerhalb des Verfahrens verwendet. Ohne zu überprüfen, wie es verwendet wird, z. wenn es tatsächlich aufgerufen wird:

class Test { 
    var closure: Any 
    init(c:()->Void) { 
     self.closure = c //Error: Non-Ecaping parameter 'c' may only be called 
    } 
} 

Durch den Verschluss auf eine generische Art Einstellung (T) ignoriert die Tatsache, dass T könnte ein Verschluss sein. Wenn es das nicht ignorieren würde, hätte es sich bei jedem generischen Argument beschweren müssen, da es sich um eine Schließung handeln könnte.

Ich frage mich, ob dies eine Arbeit um zu vermeiden, Heap-Allokation durch Flucht verursacht zu vermeiden.

Meinung basiert: Compiler Warnungen und Fehler gibt es aus einem Grund. Ich plädiere dagegen, sie zu unterdrücken, vor allem aus Gründen der vorzeitigen Optimierung wie "Umgehung der Heap-Allokation".

2

Bedeutet es, dass es als Noescape-Abschluss gilt?

Nein, sicher nicht. Es entkommt der Lebensdauer der Funktion, an die es übergeben wird (init(c:) in diesem Fall) - also per Definition, es entkommt. Sie haben es einfach nicht, wie @escaping weil nur Verschlussfunktion Argumente (das heißt Funktionsargumente, die eingegeben werden, als Funktionen selbst) zu markieren sind nicht entkommen standardmäßig (nach SE-0103).

Deshalb, weil der Verschluss entweicht, wird es jeden Staat braucht, dass es fängt Heap zugewiesen zu werden. Es gibt keine Möglichkeit, dass dieser Status stack-allokiert werden kann, da seine Lebensdauer nicht auf den aktuellen Stack-Frame beschränkt ist.

aber in Ihrem Fall, Sie vorbei nur in einer einfachen globalen Funktion, test. Hier muss keine zusätzliche Heap-Zuweisung erfolgen, da globale Funktionen statisch gespeichert werden und somit nur ein einfacher Zeiger übergeben werden muss.

Obwohl es ist erwähnenswert, dass, weil, dass Sie mit Generika arbeiten, um eine Funktion als eine gegebene allgemeine Platzhalter eingeben T wird Swift ein reabstraction Thunk verwenden, um die Aufrufkonvention zu vereinen. Dazu wird eine Heap-allokierte Box verwendet, um den Funktionswert zu speichern (genauer gehe ich dazu in this Q&A).

In einem optimierten Build jedoch appears the thunk is able to be specialised in einigen Fällen (z. B. bei direkter Verwendung einer Top-Level-Funktion), daher keine zusätzliche Heap-Allokation erforderlich.

Verwandte Themen