2016-05-04 12 views
7

ci sono due situazione mi fa confondere quando sviluppare rapido 2.2 utilizzando Xcode 7.1, vedere l'esempio di seguito, graziePerché Swift non inferenza di tipo a qualsiasi quando viene messo elemento tipo multiplo in Array

In primo luogo, l'importazione quando Fondazione, ho dichiarato un TestArray che contiene due articoli, un tipo Integer 1 e un tipo stringa "ciao", la mia domanda è perché il tipo Swift inferenza TestArray a Array (NSObject) invece di Array (qualsiasi)

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

seconda , quando rimuovo Import Foundation, il seguente codice non può essere compilato, il messaggio di errore è "Tipo di espressione è ambiguo senza più contenuto", la mia domanda è il motivo per cui Swift non inferenza di tipo a matrice (Qualsiasi) in questa situazione, grazie per l'aiuto

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

risposta

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

Any è solo un protocollo che tutti i tipi implicitamente conformi alle - non è un tipo di calcestruzzo stesso. Swift non può dedurre una matrice di tipi non concreti, che è il motivo per cui non riesce a dedurre Any, ma riesce con NSObject (Int può essere colmato al NSNumber, String può essere colmato al NSString - ed entrambi ereditano da NSObject, che è una concreta genere).

Ad esempio, considerare questo:

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

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

Poiché Foo è un tipo non-calcestruzzo, Swift non può dedurre un array di esso. Devi dire esplicitamente al compilatore ciò che si vuole il tipo di essere:

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

Avrete anche lo stesso comportamento con AnyObject (come si tratta di un protocollo che tutti classi implicitamente conformi a -, ma ancora non è un tipo concreto):

class Qux {} 
class Fox {} 

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

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

Perché Swift è in grado di dedurre una matrice di tipi non-cemento è più probabile a causa delle limitazioni esistenti di tipo non-concreto in lingua - attualmente tipi concreti sono necessari per la maggior parte operazioni non banali. See this great Q&A for an example.

Ma ad essere onesti, si dovrebbe davvero pensare di più sul fatto che si effettivamente bisogno di un array di Any. Non riesco a pensare ad una singola applicazione pratica di avere una matrice di Any, poiché tutto si conforma implicitamente agli elementi, essi devono essere sicuri di non fare nulla (non si può chiamare un metodo specifico su qualcosa che potrebbe essere qualsiasi cosa). Certo, puoi digitare il cast, ma qual è il punto nel recuperare la sicurezza del tipo che hai buttato via per cominciare?

Si dovrebbe sempre essere il tipo specifico che è possibile. Potresti creare un wrapper per i tuoi valori - questo potrebbe essere un semplice struct per racchiudere un paio di proprietà, oppure un type erasure per racchiudere tipi non concreti in un tipo pseudo-concreto. Per lo meno, dovresti prendere in considerazione la creazione del tuo protocollo a cui gli elementi dell'array sono conformi.

+2

Gli ultimi due paragrafi sollevano qui i punti più importanti. E onestamente, 'NSObject' (o' AnyObject' che non funzionerebbe qui ma lo vedo usato sempre) non è molto più specifico di 'Any'. – nhgrif

+0

@ originaluser2 la tua spiegazione è davvero utile, grazie mille – c41ux

+0

@ c41ux Felice di aiutare :) – Hamish

3

Perché non si auto riconoscerà gamma di Any

che funzionerà se si definiscono come

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

importazioni Foundation biblioteca del NS API, che converte automaticamente il 2-NSNumber e "world"-NSString, convertendolo automatico LY a schiera di NSObject

+2

1. Risposta: Divertente, chiede perché e tu dici solo perché è così. 2. Risposta: Se usi 'import Foundation',' 2' è 'Int' e' "world" 'è' String'. Solo perché non esiste un tipo nativo di Swift che può essere trovato (chissà perché non riconosce '[Any]') prende il '[NSObject]'. – Binarian

+2

@iGodric, hey, hai sbagliato.1. guarda il suo errore: "Il tipo di espressione è ambiguo senza più contenuto", Non può riconoscerlo automaticamente perché questo è il modo in cui funziona il compilatore. 2. un array di 'NSObject' deve contenere' NSObjects'. se si esegue 'import Foundation' e si esegue il prossimo codice' print (testArray [0] .dynamicType) print (testArray [1] .dynamicType) 'l'output sarà' __NSCFNumber' che è NSNumber (e non Int) e '_NSContiguousString' che è' NSString' e non String. grazie per il commento "Divertente". –

+1

A 1. Sì, ma una spiegazione che dice "così funziona il compilatore" non è una spiegazione. A 2. Che quello che hai detto è corretto, ma stai facendo delle supposizioni nel mio commento, che non ho detto. Sì in quel caso particolare quando importate Foundation e create una matrice con più tipi '2' è' NSNumber' e '" world "' è 'NSString' ma solo perché il tipo dedotto è' [AnyObject] '. Ma importare 'Foundation' non converte automaticamente' 2' in 'NSNumber' di per sé, questo è quello che sto cercando di dire. La tua risposta può essere fuorviante. Il mio primo commento potrebbe sembrare duro. – Binarian