2016-05-04 3 views
7

mehrere Typen Element setzen gibt es zwei Situation verwirren Sie mich, wenn unter Verwendung von Xcode 7.1 swift 2.2 entwickeln, benutzen Sie bitte das folgende Beispiel dankWarum Swift nicht Inferenz auf jede Art, wenn sie in Array

Zuerst sehen, wenn Import Foundation, erklärte ich eine testarray, die zwei Artikel enthält, ein Integer-Typ 1 und ein String-Typ „Hallo“, meine Frage ist, warum Inferenz Swift Typ testarray auf Array (NSObject) anstelle von Array (Any)

import Foundation 
let testArray = [1, "hello"] 
print(testArray.dynamicType) //testArray is Array<NSObject> 

Zweite , wenn ich Import Foundation entferne, kann der folgende Code nicht kompiliert werden, die Fehlermeldung lautet "Art des Ausdrucks ist mehrdeutig ohne mehr Inhalt", meine Frage warum Swift nicht Inferenz Array (any) in dieser Situation geben, vielen Dank für Hilfe

let testArray2 = [2, "world"] 
print(testArray2) 
//can't compile, error message = "Type of expression is ambiguous without more content" 

Antwort

9
/// The protocol to which all types implicitly conform. 
public typealias Any = protocol<> 

Any ist nur ein Protokoll, das alle Typen implizit entsprechen - es ist kein konkreter selbst. Swift kann nicht eine Reihe von Nicht-Beton-Typen ableiten, weshalb es nicht Any zu schließen, aber mit NSObject erfolgreich ist (Int-NSNumber überbrückt werden kann, kann String-NSString überbrückt werden - und sie erben beide von NSObject, das ist ein Beton Art).

Betrachten wir zum Beispiel diese:

protocol Foo {} 
struct Bar:Foo {} 
struct Baz:Foo {} 

let arr = [Bar(), Baz()] // error: Type of expression is ambiguous without more context 

Da Foo ein nicht-Beton-Typ ist, Swift kann eine Reihe von nicht schließen. Sie müssen explizit den Compiler sagen, was Sie ihrer Art sein wollen:

let arr:[Foo] = [Bar(), Baz()] 

Sie werden auch das gleiche Verhalten mit AnyObject erhalten (wie es ein Protokoll ist, dass alle Klassen implizit entsprechen - aber noch kein Beton-Typ):

class Qux {} 
class Fox {} 

let a = [Qux(), Fox()] // error: Type of expression is ambiguous without more context 

let a1:[AnyObject] = [Qux(), Fox()] // no error 

Warum Swift ist nicht in der Lage eine Reihe von nicht-Betone zu schließen ist höchstwahrscheinlich aufgrund der bestehenden Grenzen der nicht-Betone in der Sprache - zur Zeit Betont erforderlich sind für die meisten nicht-triviale Operationen. See this great Q&A for an example.

Aber um ehrlich zu sein, sollten Sie wirklich mehr darüber nachdenken, ob Sie tatsächlich brauchen ein Array von Any. Ich kann mir keine einzige praktische Anwendung eines Arrays von Any vorstellen, da alles, was implizit mit den Elementen übereinstimmt, garantiert nichts tun muss (Sie können keine bestimmte Methode für etwas nennen, das irgendwas sein könnte). Natürlich kannst du auch schreiben, aber was bringt es, die Typsicherheit zurückzubekommen, die du zuerst weggeworfen hast?

Sie sollten immer so typspezifisch wie möglich sein. Sie könnten einen Wrapper für Ihre Werte erstellen - dies könnte entweder ein einfaches struct sein, um ein paar Eigenschaften zu umbrechen, oder ein type erasure, um nicht konkrete Typen in einen pseudo-konkreten Typ einzubinden. Zumindest sollten Sie in Erwägung ziehen, ein eigenes Protokoll zu erstellen, dem Ihre Array-Elemente entsprechen.

+2

Die letzten zwei Absätze heben hier die wichtigsten Punkte hervor. Und ehrlich gesagt, 'NSObject' (oder' AnyObject', das hier nicht funktionieren würde, aber ich sehe es die ganze Zeit verwendet) ist nicht viel spezifischer als 'Any'. – nhgrif

+0

@ originaluser2 Ihre Erklärung ist wirklich hilfreich, vielen Dank – c41ux

+0

@ c41ux Glücklich zu helfen :) – Hamish

3

Denn es wird nicht automatisch erkennen Array von Any

es wird funktionieren, wenn Sie definieren es als

let testArray2 :[Any] = [2, "world"] 

das Foundation Bibliothek Einfuhren die NS API, die automatisch konvertiert die 2 zu NSNumber und "world" zu NSString, deren Umwandlung automatische ly auf Anordnung von NSObject

+2

1. Antwort: Komisch, er fragt warum und du sagst nur weil es so ist. 2. Antwort: Wenn Sie 'import Foundation 'verwenden, ist' 2' 'Int' und' "world'' ist' String'. Nur weil es keinen ursprünglichen Swift-Typ gibt, der gefunden werden kann (wer weiß, warum er '[Any]' nicht erkennt), braucht es das '[NSObject]'. – Binarian

+2

@iGodric, hey, du liegst falsch. Sehen Sie sich seinen Fehler an: 'Der Ausdruckstyp ist mehrdeutig ohne mehr Inhalt. Er kann ihn nicht automatisch erkennen, weil der Compiler so funktioniert. 2. Ein Array von 'NSObject' muss' NSObjects' enthalten. Wenn Sie 'import Foundation 'tun und den nächsten Code' print (testArray [0] .dynamicType) drucken (testArray [1] .dynamicType) 'Die Ausgabe wird' __NSCFNumber' sein, was NSNumber (und nicht Int) und '_NSContiguousString' ist' NSString' und nicht String. Danke für den 'Lustigen' Kommentar. –

+1

Zu 1. Ja, aber eine Erklärung, die sagt "so funktioniert der Compiler" ist keine Erklärung. Zu 2. Das, was du gesagt hast, ist richtig, aber du machst Annahmen in meinem Kommentar, den ich nicht gesagt habe. Ja in diesem speziellen Fall ist beim Importieren von Foundation und beim Erstellen eines Arrays mit mehreren Typen '2'' NSNumber' und '' world' '' NSString', aber nur, weil der abgeleitete Typ '[AnyObject]' ist. Aber das Importieren von "Foundation" konvertiert nicht automatisch "2" in "NSNumber", das ist es, was ich versuche zu sagen. Ihre Antwort kann irreführend sein. Mein erster Kommentar mag zu hart klingen. – Binarian

Verwandte Themen