Ricerca di array sicura (controllata da limiti) in Swift, tramite collegamenti opzionali?


271

Se ho un array in Swift e provo ad accedere a un indice fuori limite, c'è un errore di runtime non sorprendente:

var str = ["Apple", "Banana", "Coconut"]

str[0] // "Apple"
str[3] // EXC_BAD_INSTRUCTION

Tuttavia, avrei pensato con tutto il concatenamento e la sicurezza opzionali offerti da Swift, sarebbe banale fare qualcosa del tipo:

let theIndex = 3
if let nonexistent = str[theIndex] { // Bounds check + Lookup
    print(nonexistent)
    ...do other things with nonexistent...
}

Invece di:

let theIndex = 3
if (theIndex < str.count) {         // Bounds check
    let nonexistent = str[theIndex] // Lookup
    print(nonexistent)   
    ...do other things with nonexistent... 
}

Ma non è così: devo usare la vecchia ifdichiarazione per verificare e assicurarsi che l'indice sia inferiore a str.count.

Ho provato ad aggiungere la mia subscript()implementazione, ma non sono sicuro di come passare la chiamata all'implementazione originale o di accedere agli elementi (in base all'indice) senza utilizzare la notazione dei pedici:

extension Array {
    subscript(var index: Int) -> AnyObject? {
        if index >= self.count {
            NSLog("Womp!")
            return nil
        }
        return ... // What?
    }
}

2
Mi rendo conto che questo è leggermente OT, ma penso anche che sarebbe carino se Swift avesse una sintassi chiara per eseguire qualsiasi tipo di controllo dei limiti, inclusi gli elenchi. Abbiamo già una parola chiave adatta per questo, in. Quindi, ad esempio, se X in (1,2,7) ... o se X in myArray
Maury Markowitz,

Risposte:


652

La risposta di Alex ha buoni consigli e soluzioni per la domanda, tuttavia, mi è capitato di imbattermi in un modo migliore di implementare questa funzionalità:

Swift 3.2 e versioni successive

extension Collection {

    /// Returns the element at the specified index if it is within bounds, otherwise nil.
    subscript (safe index: Index) -> Element? {
        return indices.contains(index) ? self[index] : nil
    }
}

Swift 3.0 e 3.1

extension Collection where Indices.Iterator.Element == Index {

    /// Returns the element at the specified index if it is within bounds, otherwise nil.
    subscript (safe index: Index) -> Generator.Element? {
        return indices.contains(index) ? self[index] : nil
    }
}

Ringraziamo Hamish per aver trovato la soluzione per Swift 3 .

Swift 2

extension CollectionType {

    /// Returns the element at the specified index if it is within bounds, otherwise nil.
    subscript (safe index: Index) -> Generator.Element? {
        return indices.contains(index) ? self[index] : nil
    }
}

Esempio

let array = [1, 2, 3]

for index in -20...20 {
    if let item = array[safe: index] {
        print(item)
    }
}

45
Penso che questo meriti sicuramente attenzione - bel lavoro. Mi piace il safe:nome del parametro incluso per garantire la differenza.
Craig Otis,

11
A partire da Swift 2 (Xcode 7) questo ha bisogno di una piccola modifica:return self.indices ~= index ? self[index] : nil;
Tim

7
Per quanto riguarda la versione di Swift 3: probabilmente un prompt corner-case-only, ma comunque un prompt: ci sono casi in cui la versione di sottoscrizione "sicura" sopra non è sicura (mentre la versione di Swift 2 era): per i Collectiontipi in cui Indicessono non contiguo. Ad Setesempio, se dovessimo accedere a un elemento impostato tramite index ( SetIndex<Element>), possiamo imbatterci in eccezioni di runtime per gli indici che sono >= startIndexe < endIndex, nel qual caso il pedice sicuro non riesce (vedi ad esempio questo esempio forzato ).
venerdì

12
AVVERTIMENTO! Controllare gli array in questo modo può essere molto costoso. Il containsmetodo eseguirà l'iterazione attraverso tutti gli indici, rendendo così questo O (n). Un modo migliore è usare l'indice e contare per controllare i limiti.
Stefan Vasiljevic,

6
Per impedire la generazione di indici e l'iterazione su di essi (O (n)), è meglio usare i confronti (O (1)): i return index >= startIndex && index < endIndex ? self[index] : nil Collectiontipi hanno startIndex, endIndexche sono Comparable. Naturalmente, questo non funzionerà per alcune strane collezioni che, ad esempio, non hanno indici nel mezzo, la soluzione con indicesè più generale.
Zubko,

57

Se vuoi davvero questo comportamento, ha l'odore di un dizionario invece di un array. I dizionari ritornano nilquando si accede alle chiavi mancanti, il che ha senso perché è molto più difficile sapere se una chiave è presente in un dizionario poiché quelle chiavi possono essere qualsiasi cosa, dove in un array la chiave deve essere in un intervallo di: 0a count. Ed è incredibilmente comune iterare su questo intervallo, dove puoi essere assolutamente sicuro di avere un valore reale su ogni iterazione di un ciclo.

Penso che il motivo per cui non funziona in questo modo sia una scelta progettuale fatta dagli sviluppatori Swift. Prendi il tuo esempio:

var fruits: [String] = ["Apple", "Banana", "Coconut"]
var str: String = "I ate a \( fruits[0] )"

Se sai già che esiste l'indice, come nella maggior parte dei casi in cui usi un array, questo codice è ottimo. Tuttavia, se si accede a un pedice potrebbe tornare nilpoi si è cambiato il tipo di ritorno di Array's subscriptmetodo per essere un optional. Questo cambia il tuo codice in:

var fruits: [String] = ["Apple", "Banana", "Coconut"]
var str: String = "I ate a \( fruits[0]! )"
//                                     ^ Added

Ciò significa che dovresti scartare un facoltativo ogni volta che esegui iterazioni in un array o fai qualsiasi altra cosa con un indice noto, solo perché raramente potresti accedere a un indice fuori limite. I progettisti di Swift hanno optato per meno scartare gli optionals, a scapito di un'eccezione di runtime quando si accede a indici fuori limite. E un arresto anomalo è preferibile a un errore logico causato da un dato nilche non ti aspettavi da qualche parte nei tuoi dati.

E sono d'accordo con loro. Quindi non cambierai l' Arrayimplementazione predefinita perché spezzeresti tutto il codice che prevede valori non opzionali dagli array.

Invece, è possibile Arrayeseguire la sottoclasse e eseguire subscriptl' override per restituire un facoltativo. O, più praticamente, potresti estenderlo Arraycon un metodo non di sottoscrizione che lo fa.

extension Array {

    // Safely lookup an index that might be out of bounds,
    // returning nil if it does not exist
    func get(index: Int) -> T? {
        if 0 <= index && index < count {
            return self[index]
        } else {
            return nil
        }
    }
}

var fruits: [String] = ["Apple", "Banana", "Coconut"]
if let fruit = fruits.get(1) {
    print("I ate a \( fruit )")
    // I ate a Banana
}

if let fruit = fruits.get(3) {
    print("I ate a \( fruit )")
    // never runs, get returned nil
}

Swift 3 Update

func get(index: Int) ->T? deve essere sostituito da func get(index: Int) ->Element?


2
+1 (e accetta) per aver menzionato il problema con la modifica del tipo di ritorno subscript()in facoltativo: questo era il blocco stradale principale affrontato nel sovrascrivere il comportamento predefinito. (Non riuscivo davvero a farlo funzionare affatto. ) Stavo evitando di scrivere un get()metodo di estensione, che è la scelta ovvia in altri scenari (categorie Obj-C, chiunque?) Ma get(non è molto più grande di [, e lo rende chiaro che il comportamento potrebbe differire da quello che altri sviluppatori potrebbero aspettarsi dall'operatore di sottoscrizione Swift. Grazie!
Craig Otis,

3
Per renderlo ancora più breve, utilizzo at ();) Grazie!
Hyouuu,

7
A partire da Swift 2.0 Tè stato rinominato in Element. Solo un promemoria amichevole :)
Stas Zhukovskiy il

3
Per aggiungere a questa discussione, un altro motivo per cui il controllo dei limiti non viene inserito in Swift per restituire un facoltativo è perché il ritorno nilinvece di causare un'eccezione da un indice fuori limite sarebbe ambiguo. Poiché eg Array<String?>potrebbe anche restituire zero come membro valido della raccolta, non sarebbe possibile distinguere tra questi due casi. Se hai il tuo tipo di raccolta che sai non può mai restituire un nilvalore, ovvero è contestuale all'applicazione, puoi estendere Swift per il controllo sicuro dei limiti come indicato in questo post.
Aaron,

Funziona magnificamente
kamyFC il

20

Per basarsi sulla risposta di Nikita Kukushkin, a volte è necessario assegnare in modo sicuro indici di array e leggere da essi, ad es.

myArray[safe: badIndex] = newValue

Quindi ecco un aggiornamento alla risposta di Nikita (Swift 3.2) che consente anche di scrivere in modo sicuro su indici di array mutabili, aggiungendo il nome del parametro safe:

extension Collection {
    /// Returns the element at the specified index iff it is within bounds, otherwise nil.
    subscript(safe index: Index) -> Element? {
        return indices.contains(index) ? self[ index] : nil
    }
}

extension MutableCollection {
    subscript(safe index: Index) -> Element? {
        get {
            return indices.contains(index) ? self[ index] : nil
        }

        set(newValue) {
            if let newValue = newValue, indices.contains(index) {
                self[ index] = newValue
            }
        }
    }
}

2
Risposta estremamente sottovalutata! Questo è il modo corretto per farlo!
Reid,

14

Valido in Swift 2

Anche se a questa risposta è già stata data risposta molte volte, vorrei presentare una risposta più in linea su dove sta andando la moda della programmazione Swift, che nelle parole di Crusty¹ è: "Pensa protocolprima di tutto"

• Cosa vogliamo fare?
- Ottieni un elemento di un Arraydato indice solo quando è sicuro, e nilaltrimenti
• Su cosa dovrebbe basarsi questa funzionalità l'implementazione?
- Array subscripting
• Da dove viene questa funzione?
- La sua definizione di struct Arraynel Swiftmodulo lo ha
• Niente di più generico / astratto?
- Adotta ciò protocol CollectionTypeche lo garantisce anche
• Niente di più generico / astratto?
- Adotta protocol Indexableanche ...
• Sì, sembra il meglio che possiamo fare. Possiamo quindi estenderlo per avere questa funzione che vogliamo?
- Ma abbiamo tipi (no Int) e proprietà molto limitati (nocount) con cui lavorare ora!
• Sarà abbastanza. Lo stdlib di Swift è fatto abbastanza bene;)

extension Indexable {
    public subscript(safe safeIndex: Index) -> _Element? {
        return safeIndex.distanceTo(endIndex) > 0 ? self[safeIndex] : nil
    }
}

¹: non vero, ma dà l'idea


2
Come novizio di Swift non capisco questa risposta. Cosa rappresenta il codice alla fine? È una soluzione e, in tal caso, come la uso effettivamente?
Thomas Tempelmann,

3
Siamo spiacenti, questa risposta non è più valida per Swift 3, ma il processo lo è sicuramente. L'unica differenza è che ora dovresti Collectionprobabilmente fermarti alle :)
DeFrenZ

11
extension Array {
    subscript (safe index: Index) -> Element? {
        return 0 <= index && index < count ? self[index] : nil
    }
}
  • O (1) prestazione
  • digita sicuro
  • gestisce correttamente Optionals per [MyType?] (restituisce MyType ??, che può essere scartato su entrambi i livelli)
  • non causa problemi per i set
  • codice conciso

Ecco alcuni test che ho eseguito per te:

let itms: [Int?] = [0, nil]
let a = itms[safe: 0] // 0 : Int??
a ?? 5 // 0 : Int?
let b = itms[safe: 1] // nil : Int??
b ?? 5 // nil : Int?
let c = itms[safe: 2] // nil : Int??
c ?? 5 // 5 : Int?

10
  • Poiché le matrici possono memorizzare valori nulli, non ha senso restituire un valore nullo se una chiamata di array [indice] è fuori limite.
  • Poiché non sappiamo come un utente vorrebbe gestire i problemi fuori limite, non ha senso utilizzare operatori personalizzati.
  • Al contrario, utilizzare il flusso di controllo tradizionale per scartare oggetti e garantire la sicurezza del tipo.

if let index = array.checkIndexForSafety (index: Int)

  let item = array[safeIndex: index] 

if let index = array.checkIndexForSafety (index: Int)

  array[safeIndex: safeIndex] = myObject
extension Array {

    @warn_unused_result public func checkIndexForSafety(index: Int) -> SafeIndex? {

        if indices.contains(index) {

            // wrap index number in object, so can ensure type safety
            return SafeIndex(indexNumber: index)

        } else {
            return nil
        }
    }

    subscript(index:SafeIndex) -> Element {

        get {
            return self[index.indexNumber]
        }

        set {
            self[index.indexNumber] = newValue
        }
    }

    // second version of same subscript, but with different method signature, allowing user to highlight using safe index
    subscript(safeIndex index:SafeIndex) -> Element {

        get {
            return self[index.indexNumber]
        }

        set {
            self[index.indexNumber] = newValue
        }
    }

}

public class SafeIndex {

    var indexNumber:Int

    init(indexNumber:Int){
        self.indexNumber = indexNumber
    }
}

1
Approccio interessante Qualche motivo SafeIndexè una classe e non una struttura?
stef

8

Swift 4

Un'estensione per chi preferisce una sintassi più tradizionale:

extension Array {

    func item(at index: Int) -> Element? {
        return indices.contains(index) ? self[index] : nil
    }
}

non è necessario vincolare gli elementi dell'array a equatable per verificare se gli indici contengono il suo indice.
Leo Dabus,

sì - buon punto - sarebbe necessario solo per altri metodi sicuri come deleteObject, ecc.
Matjan

5

Ho trovato l'array sicuro ottenere, impostare, inserire, rimuovere molto utile. Preferisco accedere e ignorare gli errori poiché tutto il resto diventa presto difficile da gestire. Muggito di codice completo

/**
 Safe array get, set, insert and delete.
 All action that would cause an error are ignored.
 */
extension Array {

    /**
     Removes element at index.
     Action that would cause an error are ignored.
     */
    mutating func remove(safeAt index: Index) {
        guard index >= 0 && index < count else {
            print("Index out of bounds while deleting item at index \(index) in \(self). This action is ignored.")
            return
        }

        remove(at: index)
    }

    /**
     Inserts element at index.
     Action that would cause an error are ignored.
     */
    mutating func insert(_ element: Element, safeAt index: Index) {
        guard index >= 0 && index <= count else {
            print("Index out of bounds while inserting item at index \(index) in \(self). This action is ignored")
            return
        }

        insert(element, at: index)
    }

    /**
     Safe get set subscript.
     Action that would cause an error are ignored.
     */
    subscript (safe index: Index) -> Element? {
        get {
            return indices.contains(index) ? self[index] : nil
        }
        set {
            remove(safeAt: index)

            if let element = newValue {
                insert(element, safeAt: index)
            }
        }
    }
}

test

import XCTest

class SafeArrayTest: XCTestCase {
    func testRemove_Successful() {
        var array = [1, 2, 3]

        array.remove(safeAt: 1)

        XCTAssert(array == [1, 3])
    }

    func testRemove_Failure() {
        var array = [1, 2, 3]

        array.remove(safeAt: 3)

        XCTAssert(array == [1, 2, 3])
    }

    func testInsert_Successful() {
        var array = [1, 2, 3]

        array.insert(4, safeAt: 1)

        XCTAssert(array == [1, 4, 2, 3])
    }

    func testInsert_Successful_AtEnd() {
        var array = [1, 2, 3]

        array.insert(4, safeAt: 3)

        XCTAssert(array == [1, 2, 3, 4])
    }

    func testInsert_Failure() {
        var array = [1, 2, 3]

        array.insert(4, safeAt: 5)

        XCTAssert(array == [1, 2, 3])
    }

    func testGet_Successful() {
        var array = [1, 2, 3]

        let element = array[safe: 1]

        XCTAssert(element == 2)
    }

    func testGet_Failure() {
        var array = [1, 2, 3]

        let element = array[safe: 4]

        XCTAssert(element == nil)
    }

    func testSet_Successful() {
        var array = [1, 2, 3]

        array[safe: 1] = 4

        XCTAssert(array == [1, 4, 3])
    }

    func testSet_Successful_AtEnd() {
        var array = [1, 2, 3]

        array[safe: 3] = 4

        XCTAssert(array == [1, 2, 3, 4])
    }

    func testSet_Failure() {
        var array = [1, 2, 3]

        array[safe: 4] = 4

        XCTAssert(array == [1, 2, 3])
    }
}

3
extension Array {
  subscript (safe index: UInt) -> Element? {
    return Int(index) < count ? self[Int(index)] : nil
  }
}

L'uso dell'estensione sopra menzionata restituisce zero se in qualsiasi momento l'indice va fuori limite.

let fruits = ["apple","banana"]
print("result-\(fruits[safe : 2])")

risultato - zero


3

Mi rendo conto che questa è una vecchia domanda. Sto usando Swift5.1 a questo punto, l'OP era per Swift 1 o 2?

Avevo bisogno di qualcosa del genere oggi, ma non volevo aggiungere un'estensione in scala reale solo per un posto e volevo qualcosa di più funzionale (più thread sicuro?). Inoltre, non avevo bisogno di proteggermi dagli indici negativi, ma solo quelli che potrebbero essere oltre la fine di un array:

let fruit = ["Apple", "Banana", "Coconut"]

let a = fruit.dropFirst(2).first // -> "Coconut"
let b = fruit.dropFirst(0).first // -> "Apple"
let c = fruit.dropFirst(10).first // -> nil

Per coloro che discutono di Sequenze con zero, cosa fai riguardo alle proprietà firste lastche restituiscono zero per raccolte vuote?

Mi è piaciuto perché potevo semplicemente prendere cose esistenti e usarle per ottenere il risultato che volevo. So anche che dropFirst (n) non è una copia dell'intera collezione, solo una porzione. E poi il comportamento già esistente di prima prende il sopravvento per me.


1

Penso che questa non sia una buona idea. Sembra preferibile creare un codice solido che non provochi nel tentativo di applicare indici fuori limite.

Si prega di considerare che la mancata silenziosità di un errore di questo tipo (come suggerito dal codice sopra riportato) nilè soggetta alla produzione di errori ancora più complessi e più intrattabili.

Potresti eseguire l'override in un modo simile a quello che hai usato e scrivere gli abbonamenti a modo tuo. L'unico inconveniente è che il codice esistente non sarà compatibile. Penso che trovare un hook per sovrascrivere il generico x [i] (anche senza un preprocessore di testo come in C) sarà una sfida.

Il più vicino a cui riesco a pensare è

// compile error:
if theIndex < str.count && let existing = str[theIndex]

EDIT : Questo funziona davvero. One-liner !!

func ifInBounds(array: [AnyObject], idx: Int) -> AnyObject? {
    return idx < array.count ? array[idx] : nil
}

if let x: AnyObject = ifInBounds(swiftarray, 3) {
    println(x)
}
else {
    println("Out of bounds")
}

6
Non sarei d'accordo - il punto dell'associazione facoltativa è che riesce solo se la condizione è soddisfatta. (Per un facoltativo, significa che esiste un valore.) L'uso di un if letin questo caso non rende il programma più complesso, né gli errori più intrattabili. Condensa semplicemente il tradizionale ifcontrollo dei limiti a due istruzioni e la ricerca effettiva in una frase condensata a riga singola. Esistono casi (particolarmente lavorano in una UI) dove è normale per un indice di essere fuori limite, come chiedere una NSTableViewper il selectedRowsenza selezione.
Craig Otis,

3
@Mundi questo sembra essere un commento, piuttosto che una risposta alla domanda del PO.
jlehr,

1
@CraigOtis Non sono sicuro di essere d'accordo. È possibile scrivere questo controllo in modo succinto in una "frase concentrata a riga singola", ad es. Usando countElementso come l'OP ha fatto count, semplicemente non nel modo in cui il linguaggio definisce la scrittura dei pedici dell'array.
Mundi,

1
@jlehr Forse no. È giusto mettere in discussione l'intenzione o la saggezza di un problema posto.
Mundi,

2
@Mundi Heh, soprattutto se successivamente lo modifichi per rispondere effettivamente alla domanda. :-)
jlehr

1

Ho riempito l'array con nils nel mio caso d'uso:

let components = [1, 2]
var nilComponents = components.map { $0 as Int? }
nilComponents += [nil, nil, nil]

switch (nilComponents[0], nilComponents[1], nilComponents[2]) {
case (_, _, .Some(5)):
    // process last component with 5
default:
    break
}

Controlla anche l'estensione dell'abbonamento con l' safe:etichetta di Erica Sadun / Mike Ash: http://ericasadun.com/2015/06/01/swift-safe-array-indexing-my-favorite-thing-of-the-new-week/


0

L'elenco "Modifiche comunemente rifiutate" per Swift contiene una menzione della modifica dell'accesso al pedice Array per restituire un facoltativo anziché il crash:

Rendere l' Array<T>accesso dell'abbonamento restituito T?o T!invece di T: L'attuale comportamento dell'array è intenzionale , poiché riflette accuratamente il fatto che l'accesso all'array fuori limite è un errore logico. La modifica del comportamento attuale rallenterebbe gli Arrayaccessi a un livello inaccettabile. Questo argomento è stato discusso più volte prima, ma è molto improbabile che venga accettato.

https://github.com/apple/swift-evolution/blob/master/commonly_proposed.md#strings-characters-and-collection-types

Quindi l'accesso di base al pedice non cambierà per restituire un facoltativo.

Tuttavia, il team / comunità Swift sembra aperto all'aggiunta di un nuovo modello di accesso facoltativo di ritorno ad Array, tramite una funzione o un pedice.

Questo è stato proposto e discusso sul forum Swift Evolution qui:

https://forums.swift.org/t/add-accessor-with-bounds-check-to-array/16871

In particolare, Chris Lattner ha dato all'idea un "+1":

D'accordo, l'ortografia suggerita più frequentemente per questo è yourArray[safe: idx]:, che mi sembra grandioso. Sono molto +1 per aggiungere questo.

https://forums.swift.org/t/add-accessor-with-bounds-check-to-array/16871/13

Quindi questo potrebbe essere possibile fuori dalla scatola in alcune versioni future di Swift. Incoraggerei chiunque voglia contribuire a quel thread Swift Evolution.


0

Per propagare il motivo per cui le operazioni falliscono, gli errori sono migliori degli opzionali. Gli abbonamenti non possono generare errori, quindi deve essere un metodo.

public extension Collection {
  /// - Returns: same as subscript, if index is in bounds
  /// - Throws: CollectionIndexingError
  func element(at index: Index) throws -> Element {
    guard indices.contains(index)
    else { throw CollectionIndexingError() }

    return self[index]
  }
}

/// Thrown when `element(at:)` is called with an invalid index.
public struct CollectionIndexingError: Error { }
XCTAssertThrowsError( try ["🐾", "🥝"].element(at: 2) )

let optionals = [1, 2, nil]
XCTAssertEqual(try optionals.element(at: 0), 1)

XCTAssertThrowsError( try optionals.element(at: optionals.endIndex) )
{ XCTAssert($0 is CollectionIndexingError) }

0

Non so perché nessuno, ha creato un'estensione che ha anche un setter per far crescere automaticamente l'array

extension Array where Element: ExpressibleByNilLiteral {
    public subscript(safe index: Int) -> Element? {
        get {
            guard index >= 0, index < endIndex else {
                return nil
            }

            return self[index]
        }

        set(newValue) {
            if index >= endIndex {
                self.append(contentsOf: Array(repeating: nil, count: index - endIndex + 1))
            }

            self[index] = newValue ?? nil
        }
    }
}

L'utilizzo è semplice e funziona a partire da Swift 5.1

var arr:[String?] = ["A","B","C"]

print(arr) // Output: [Optional("A"), Optional("B"), Optional("C")]

arr[safe:10] = "Z"

print(arr) // [Optional("A"), Optional("B"), Optional("C"), nil, nil, nil, nil, nil, nil, nil, Optional("Z")]

Nota: è necessario comprendere il costo delle prestazioni (sia in termini di tempo / spazio) durante la crescita rapida di un array - ma per piccoli problemi a volte è necessario solo far sì che Swift smetta di spostarsi nel piede


-1

Ho creato una semplice estensione per l'array

extension Array where Iterator.Element : AnyObject {
    func iof (_ i : Int ) -> Iterator.Element? {
        if self.count > i {
            return self[i] as Iterator.Element
        }
        else {
            return nil
        }
    }

}

funziona perfettamente come progettato

Esempio

   if let firstElemntToLoad = roots.iof(0)?.children?.iof(0)?.cNode, 

-1

Swift 5 Utilizzo

extension WKNavigationType {
    var name : String {
        get {
            let names = ["linkAct","formSubm","backForw","reload","formRelo"]
            return names.indices.contains(self.rawValue) ? names[self.rawValue] : "other"
        }
    }
}

è finito ma volevo davvero fare qualcosa di simile

[<collection>][<index>] ?? <default>

ma poiché la collezione è contestuale, credo sia corretta.


In che modo questa risposta è diversa da quella accettata? Per quanto mi riguarda, sembra esattamente lo stesso (duplicato).
Legonaftik,

-1

Quando hai solo bisogno di ottenere valori da un array e non ti dispiace una piccola penalità delle prestazioni (cioè se la tua raccolta non è enorme), c'è un'alternativa basata su dizionario che non comporta (un troppo generico, per il mio gusto) estensione collezione:

// Assuming you have a collection named array:
let safeArray = Dictionary(uniqueKeysWithValues: zip(0..., array))
let value = safeArray[index] ?? defaultValue;
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.