2016-07-15 15 views
2
protocol Test{ 

    var t: Int {set get} 

} 

struct A: Test{ 

    var t: Int 

} 

struct B: Test{ 

    var t: Int 
    var s: String 

} 

let a = A(t: 1) 
let b = B(t: 2, s: "1") 

let c = a as Test 

let d: [Test] = [a, b] 

let e: [A] = [a, a] 

let f = e as [Test] 

let g = e as! [Test] 

"lass f = e wie [Test], lass g = e wie! [Test]" immer falsch. Ich habe eine Funktion, an die ich einen [Test] senden muss. Convert A to Test ist einfach zu verwenden als. Aber wenn es zu Array kommt, muss ich alle Daten durchlaufen. Gibt es einen guten Weg, um [A] zu [Test] zu konvertieren.Typumwandlung bei Verwendung des Protokolls in Swift

Antwort

6

-Code Verschiedene Antwort der ist richtig, aber es ist auch wichtig zu verstehen, warum Sie nicht nur die Daten ohne etwas neu interpretieren kann tun ein O (n) Umwandlung obwohl zu gehen und wickeln jedes Element in eine Box.

[A] ist ein Array mit Elementen der Größe A. Also, mehr oder weniger, A[1] ist am Speicherort A[0] + sizeof(A) (das ist nicht genau richtig, aber so tun, als wäre es; es wird die Dinge einfacher machen).

[Test] muss in der Lage sein etwas zu halten, die dem Protokoll entspricht. Es könnte die Größe von A sein, es könnte die Größe von B sein, die größer ist. Um dies zu erreichen, erstellt es eine Box, die "etwas enthält, das Test entspricht". Die Box hat eine bekannte Größe, und sie muss das Ding, auf das sie zeigt, haufenweise zuweisen (oder vielleicht nicht; hängt davon ab), aber es wird nicht die gleiche Größe haben wie A und B, also das Layout von [Test] im Speicher muss sich von dem Layout [A] oder [B] unterscheiden.

Jetzt as [Test] könnte tun, dass O (n) für Sie gehen und eine Kopie dann richtig zwingen. Oder es verzögert die Kopie bis zum ersten Mal, wenn Sie etwas geändert haben, aber es wäre viel komplizierter und würde ein O (n) (möglicherweise teures, möglicherweise Speicherzuweisungs) -Ereignis in einem as begraben, das sich anfühlt wie O (1) und keinen Speicher zuweisen. Also gibt es Gründe, das nicht zu tun.

Eines Tages werden sie es vielleicht tun, um die Dinge für den Anrufer einfacher zu machen, aber es gibt Kosten in der Leistung und Komplexität, und so macht es heute nicht und Sie müssen die Karte selbst machen.

Wenn Sie ein viel tiefer tauchen Sie ein in diese Dinge wollen, mit mehr Details, wie dieses Feld funktioniert (und weniger „so tun, es ist einfacher, als es ist“), siehe Understanding Swift Performance von WWDC 2016.

+0

Vielen Dank für Ihre Antwort. –

+0

Große Einsicht, ich liebe es, die grundlegenden Überlegungen hinter solchen Dingen zu sehen – Alexander

+1

Ab Swift 3 (oder sogar Swift 2.3?) Können Sie ein ganzes Array in ein Array eines Protokolltyps konvertieren. –

3

Sie können einen Array-Großhandel nicht so konvertieren. Verwenden Sie map:

let f = e.map { $0 as Test } // f is now a [Test] array 
+0

Leider aber, warum ich Ich darf [A] nicht direkt in [Test] umwandeln. –

+0

Das müssen Sie das Compiler-Team bei Apple –

+0

fragen Gute Nachrichten können Sie! Sie haben dieses Jahr auf der WWDC darüber gesprochen. Siehe Funktionsweise von Swift. –

Verwandte Themen