2016-02-02 21 views
10

Comprendo che le tuple di Swift servono, ad esempio, come un modo semplice per una funzione per restituire più valori. Tuttavia, al di là di questo "aspetto della semplicità", non vedo molto bene la necessità di utilizzare tuple anziché strutture.Tuple vs Struct in Swift

Pertanto, la mia domanda: in termini di progettazione, esiste uno scenario in cui le tuple sono chiaramente una scelta migliore delle strutture?

+2

Direi a me stesso che le tuple sono utili solo per le strutture dati utilizzate solo localmente; che altrimenti è meglio avere tutte le strutture dati correttamente definite e "etichettate" come strutture o classi, invece di farle "fluttuare come tuple anonimi". Ma non sono sicuro di non sbagliare ... – George

+1

Penso che l'aspetto della semplicità sia di cosa si tratta :) Non è necessario definire una struttura, meno codice, veloce. Swift ha molte caratteristiche che servono allo scopo della semplicità. –

risposta

6

Questa domanda di natura un po ' "discussione", ma Aggiungerò due punti a favore a volte preferendo le tuple sulle strutture.


nativo conformità equatable per le tuple di dimensioni limitate

In Swift 2.2, tuple fino alla taglia 6 sarà nativamente equatable, dato che si tratta di membri sono equatable

Ciò significa che a volte le tuple saranno la scelta naturale sull'uso di costrutti più piccoli in un ambito limitato.

E.g. si consideri il seguente esempio, utilizzando (1): una struttura

struct Foo { 
    var a : Int = 1 
    var b : Double = 2.0 
    var c : String = "3" 
} 

var a = Foo() 
var b = Foo() 

// a == b // error, Foo not Equatable 

/* we can naturally fix this by conforming Foo to Equatable, 
    but this needs a custom fix and is not as versatile as just 
    using a tuple instead. For some situations, the latter will 
    suffice, and is to prefer.         */ 
func == (lhs: Foo, rhs: Foo) -> Bool { 
    return lhs.a == rhs.a && lhs.b == rhs.b && lhs.c == rhs.c 
} 

e (2): una tupla

/* This will be native in Swift 2.2 */ 
@warn_unused_result 
public func == <A: Equatable, B: Equatable, C: Equatable>(lhs: (A,B,C), rhs: (A,B,C)) -> Bool { 
    return lhs.0 == rhs.0 && lhs.1 == rhs.1 && lhs.2 == rhs.2 
} 
/* end of native part ...   */ 

var aa = (1, 2.0, "3") 
var bb = (1, 2.0, "3") 

aa == bb // true 
aa.0 = 2 
aa == bb // false 

accesso generico a diverse tuple tipo: più versatile per diverse strutture di tipo

Da quanto sopra (confrontare le funzioni ==) appare anche In questo modo è facile lavorare con le tuple nel contesto dei generici, dato che possiamo accedere alle loro proprietà anonime dei membri usando i suffissi .0, .1 ...; mentre per una struttura, il modo più semplice per simulare questo comportamento diventa rapidamente piuttosto complesso, che richiede strumenti come l'introspezione di runtime e così via, vedere e.g. this.

+0

È interessante. Grazie – George

+0

I tuple nei parametri e nei ritorni delle funzioni possono rendere molto chiaro ciò che farà la funzione. 'func multiply (aNumber number: Int, di anotherNumber: Int) -> Int'. Come 'struct' questo non sarebbe affatto chiaro. 'func multiply (twoNumbers: TwoNumbersStruct) -> Int' –

0

Considerate questo, java all'obiettivo-C. Quando devi collegarti a questo tipo di origine dati nel tuo progetto (perché hai un enorme codice base in Android e non vuoi o non puoi fare tutto da zero), ti ritrovi con origini dati di tipi java (come ad esempio l'hashmap) , quelli sono fondamentalmente typedef dai tipi obiettivo-c. Questo non è facilmente collegabile in swift a seconda di quello che hai, se vuoi avere una bella matrice per la tua collezione, una serie di tuple che saranno riempite da java datasource possono essere belle. Un piccolo esempio di codice per illustrare questo:

var myJavaVar = JavaUtilLinkedHashMap() 
var headerArray : [(varName : String, param : Int, varId : jlong)] = [] 


myJavaVar = myStaticMethodToGetMyVar 

    // get var array 
    let keySetJava = myJavaVar.keySet().toArray() 
    for jCounter in 0..<Int(myJavaVar.size()){ 
     // id for index 
     let key : Int = keySetJava.objectAtIndex(UInt(jCounter)) as! Int 
     let varId = jlong.init(key) 
     let varName = myMethodToGetName(varId) 
     let myParam : Int = myJavaVar.getWithId(keySetJava.objectAtIndex(UInt(jCounter))) as! Int 
     // append data to the array 
     headerArray.append((varName: categoryName, param : myParam,duration: duration, varId: varId)) 
    } 

È quindi possibile ottenere i dati di questo tipo (nel metodo CollectionView):

let time = headerArray[indexPath.section].param 
+0

Ma cosa ti impedisce di definire una struct e usarla nell'array, invece di usare la tupla? E perché una tupla è migliore di una struttura? Mi sembra che la tupla renda il codice più difficile da leggere (che è soggettivo, lo so). – George

+0

Usare una tupla era già un rompicoglioni e vuoi usare una struttura per questo? Questo è solo per la cella di intestazione, ti lascio immaginare come è quando devi riempire il normale array di celle. Come può avere un parametro denominato che rende il codice più difficile da leggere? –

+0

Puoi semplicemente definire una struttura denominata HeaderData (per esempio) con i membri varName, param e varId. Avete: var headerArray: [HeaderData] = [] – George