선택적 바인딩을 통해 Swift에서 안전 (경계 검사) 배열 조회?


271

Swift에 배열이 있고 범위를 벗어난 인덱스에 액세스하려고하면 예기치 않은 런타임 오류가 있습니다.

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

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

그러나 Swift가 제공하는 모든 옵션 체인과 안전 을 생각 했을 것입니다.

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

대신에:

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

그러나 이것은 사실이 아닙니다. 저는 ol ' if문을 사용하여 색인이보다 작거나 같은지 확인해야합니다 str.count.

subscript()구현을 추가하려고 시도했지만 호출을 원래 구현으로 전달하거나 첨자 표기법을 사용하지 않고 항목 (인덱스 기반)에 액세스하는 방법을 모르겠습니다.

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

2
나는 이것이 약간 OT임을 알고 있지만 Swift가 목록을 포함하여 모든 종류의 바운드 검사를 수행하는 명확한 구문을 가지고 있다면 좋을 것이라고 생각합니다. 예를 들어 X가 (1,2,7)에 있거나 X가 myArray에있는 경우
Maury Markowitz

답변:


652

Alex의 답변 에는 질문에 대한 좋은 조언과 해결책이 있지만이 기능을 구현하는 더 좋은 방법을 발견했습니다.

스위프트 3.2 이상

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
    }
}

스위프트 3.0 및 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
    }
}

Swift 3 용 솔루션을 개발 한 Hamish에게 감사의 뜻을 전 합니다.

스위프트 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
    }
}

let array = [1, 2, 3]

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

45
나는 이것이 분명히 주목할 가치가 있다고 생각합니다. safe:차이점을 보장하기 위해 포함 된 매개 변수 이름을 좋아합니다 .
Craig Otis

11
스위프트 2 (Xcode 7) 기준으로 약간의 수정이 필요합니다.return self.indices ~= index ? self[index] : nil;
Tim

7
스위프트 3 버전에 대해서 : 가능성이 코너의 경우 전용 프롬프트하지만 프롬프트 그럼에도 불구하고 : 위의 "안전"첨자 버전 (스위프트 2 버전이었던 반면) 안전하지입니다 경우가 있습니다에 대한 Collection(가) 유형 Indices입니다 인접하지 않습니다. 예를 Set들어, 인덱스 ( SetIndex<Element>) 로 set 요소에 액세스하는 경우 >= startIndex및의 인덱스에 대해 런타임 예외가 발생할 수 있으며이 < endIndex경우 안전한 아래 첨자가 실패합니다 (예 : 이 예제 참조 ).
dfri

12
경고! 이 방법으로 배열을 확인하면 실제로 비용이 많이들 수 있습니다. 이 contains방법은 모든 지수를 반복하여 이것을 O (n)으로 만듭니다. 더 좋은 방법은 인덱스를 사용하여 범위를 확인하는 것입니다.
Stefan Vasiljevic

6
인덱스를 생성하고 그들 반복 방지하기 위해 (O (N)), 더 나은 사용 비교에의 (O (1)) : return index >= startIndex && index < endIndex ? self[index] : nil Collection유형이를 startIndex, endIndex있습니다 Comparable. 물론, 이것은 중간에 인덱스가없는 솔루션 indices이 더 일반적인 솔루션과 같은 이상한 컬렉션에는 작동하지 않습니다 .
zubko 2016 년

57

이 동작을 정말로 원한다면 배열 대신 사전을 원하는 것처럼 냄새가납니다. 사전 반환 nil에 접근하는 열쇠가 어디에 배열의 키, 무엇이든 될 수 있기 때문에이 키가 사전에 존재 알고 더 힘들어 때문에 의미가있는 키가없는 경우 필수 :의 범위 0count. 그리고 그것은 당신이 할 수있는 범위, 반복하는 매우 일반적입니다 확신 루프의 각 반복에 실제 값을 가지고 있습니다.

이 방법으로 작동하지 않는 이유는 Swift 개발자가 선택한 디자인 선택이라고 생각합니다. 예를 들어 보자.

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

배열을 사용하는 대부분의 경우처럼 인덱스가 존재한다는 것을 이미 알고 있다면이 코드가 좋습니다. 첨자에 액세스하는 가능성이 반환 할 경우, nil당신은 반환 형식 변경Arraysubscript옵션으로 방법을. 코드가 다음과 같이 변경됩니다.

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

즉, 범위를 벗어난 인덱스에 거의 액세스 할 수 없기 때문에 배열을 반복하거나 알려진 인덱스로 다른 작업을 수행 할 때마다 선택 사항을 래핑 해제해야합니다. Swift 설계자는 범위를 벗어난 인덱스에 액세스 할 때 런타임 예외를 희생하면서 옵션의 언 래핑을 줄 이도록 선택했습니다. 그리고 nil데이터 어딘가에서 예상하지 못한 논리 오류보다 충돌이 바람직합니다 .

그리고 나는 그들에 동의합니다. 따라서 Array선택 사항이 아닌 값을 기대하는 모든 코드를 배열에서 분리하므로 기본 구현을 변경하지 않습니다 .

대신에 서브 클래스 Array를 작성하고 subscript옵션을 리턴하도록 대체 할 수 있습니다 . 또는 더 실제로 Array는이를 수행하는 비 첨자 방법으로 확장 할 수 있습니다 .

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
}

스위프트 3 업데이트

func get(index: Int) ->T? 로 교체해야합니다 func get(index: Int) ->Element?


2
반환 유형을 subscript()선택 사항 으로 변경하는 문제를 언급 한 경우 +1 (및 수락) -기본 동작을 재정의하는 데 직면 한 주요로드 블록입니다. (실제로는 전혀 작동 할 수 없었 습니다. ) get()확장 방법을 작성 하지 않았습니다 . 다른 방법 (Obj-C 범주, 누구?)에서 명백한 선택이지만 ~ get(보다 크지 않으며 확장 [합니다. 동작이 다른 개발자가 Swift 첨자 연산자에서 기대할 수있는 것과 다를 수 있음을 분명히하십시오. 감사합니다!
Craig Otis

3
더 짧게 만들려면 at ();)을 사용하십시오. 감사합니다!
hyouuu

7
Swift 2.0 T에서로 이름이 변경되었습니다 Element. 그냥 친절한 알림 :)
Stas Zhukovskiy

3
이 토론에 추가하기 위해 바운드 검사가 Swift에 구워 져서 선택 사항을 반환하지 않는 또 다른 이유는 nil범위를 벗어난 인덱스에서 예외를 발생시키는 대신 반환 하는 것이 모호하기 때문입니다. 예를 들어 Array<String?>컬렉션의 유효한 멤버로 nil을 반환 할 수도 있으므로이 두 경우를 구별 할 수 없습니다. nil값을 반환 할 수없는 고유 한 컬렉션 유형이있는 경우 응용 프로그램과 관련하여 Swift를 확장하여이 게시물에서 답변 한대로 안전한 범위 검사를 수행 할 수 있습니다.
Aaron

아름답게 작동
kamyFC

20

Nikita Kukushkin의 답변을 바탕으로 때로는 때로는 색인뿐만 아니라 배열 색인에 안전하게 할당해야합니다.

myArray[safe: badIndex] = newValue

다음은 safe : 매개 변수 이름을 추가하여 가변 배열 인덱스에 안전하게 쓸 수있는 Nikita의 답변 (Swift 3.2)에 대한 업데이트입니다.

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
매우 과소 평가 된 답변! 이것이 올바른 방법입니다.
Reid

14

스위프트 2에서 유효

이것은 이미 시간을 많이 대답되었지만, 나는 피 각질의 words¹에있는 스위프트 프로그래밍의 패션이 어디로 가는지에 라인에서 더 많은 답을 제시하고 싶습니다 : "생각해 protocol최초의"

• 우리는 무엇을하고 싶은가?
- 안전 할 때만 주어진 인덱스 의 요소를 가져 Array옵니다. nil그렇지 않으면
•이 기능은 무엇을 구현해야합니까?
- Array subscript보내고
그것은 어디에서이 기능을 얻을 않습니다 •?
- 모듈 의 정의는 다음 struct Array과 같습니다.Swift
• 더 일반적인 / 추상적 인 것은 없습니까?
- 그것은 또한 protocol CollectionType그것을 보장합니다 채택
• 더 일반적인 / 추상적 인 것은 없습니까?
- 그것은 또한 채택 protocol Indexable한다 ...
그렇습니다, 우리가 할 수있는 최선의 소리. 그런 다음 원하는 기능을 갖도록 확장 할 수 있습니까?
- 그러나 우리는 매우 유형 (없음 제한 Int없음 ()와 속성을count)와 함께 작동합니다!
• 충분할 것입니다. Swift의 stdlib는 꽤 잘 수행됩니다.)

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

¹ : 사실이 아니지만 아이디어를 제공합니다.


2
스위프트 초보자로서 나는이 답변을 이해하지 못합니다. 마지막 코드는 무엇을 나타 냅니까? 이것이 해결책입니까? 그렇다면 실제로 어떻게 사용합니까?
Thomas Tempelmann

3
죄송합니다.이 답변은 Swift 3에서 더 이상 유효하지 않지만 그 과정은 확실합니다. 유일한 차이점은 이제 당신은 Collection아마 멈춰야한다는 것입니다 :)
DeFrenZ

11
extension Array {
    subscript (safe index: Index) -> Element? {
        return 0 <= index && index < count ? self[index] : nil
    }
}
  • O (1) 성능
  • 안전한 타입
  • [MyType?]에 대한 Optionals를 올바르게 처리합니다 (MyType ??을 반환합니다. 두 수준에서 모두 줄 바꿈 할 수 없음).
  • 세트에 문제를 일으키지 않습니다
  • 간결한 코드

다음은 내가 당신을 위해 실행 한 테스트입니다.

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
  • 배열은 nil 값을 저장할 수 있기 때문에 array [index] 호출이 범위를 벗어난 경우 nil을 반환하는 것은 의미가 없습니다.
  • 사용자가 범위를 벗어난 문제를 처리하는 방법을 모르기 때문에 사용자 지정 연산자를 사용하는 것은 적합하지 않습니다.
  • 반대로, 포장 풀기 대상물에는 기존의 제어 흐름을 사용하고 유형 안전을 보장하십시오.

index = array.checkIndexForSafety (index : Int) 인 경우

  let item = array[safeIndex: index] 

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
재미있는 접근법. 어떤 이유 SafeIndex가 클래스가 아닌 구조체입니까?
stef

8

스위프트 4

보다 전통적인 구문을 선호하는 사람들을위한 확장 :

extension Array {

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

인덱스에 인덱스가 포함되어 있는지 확인하기 위해 배열 요소를 동일하게 제한 할 필요는 없습니다.
Leo Dabus

예-좋은 지적
-deleteObject

5

안전한 배열 get, set, insert, remove가 매우 유용하다는 것을 알았습니다. 다른 모든 것이 곧 관리가 어려워 지므로 오류를 기록하고 무시하는 것을 선호합니다. 풀 코드 벨로우

/**
 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)
            }
        }
    }
}

테스트

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
  }
}

위의 언급을 사용하면 언제든지 색인이 범위를 벗어나면 nil을 반환합니다.

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

결과-nil


3

나는 이것이 오래된 질문이라는 것을 알고 있습니다. 이 시점에서 Swift5.1을 사용하고 있는데 OP는 Swift 1 또는 2입니까?

나는 오늘 이와 같은 것이 필요했지만 한 곳에서 풀 스케일 확장을 추가하고 싶지 않고 더 기능적인 것을 원했습니다 (더 스레드 안전합니까?). 또한 부정적인 지수로부터 보호 할 필요가 없었으며 배열의 끝을 지났을 수도 있습니다.

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

nil이있는 시퀀스에 대해 논쟁하는 사람들 은 빈 컬렉션에 대해 nil을 반환 하는 firstlast속성 에 대해 무엇을합니까 ?

나는 기존의 것을 잡아서 원하는 결과를 얻는 데 사용할 수 있기 때문에 이것을 좋아했습니다. 또한 dropFirst (n)은 전체 컬렉션 복사본이 아니라 슬라이스 일뿐입니다. 그리고 이미 존재하는 첫 번째 행동이 나를 대신합니다.


1

나는 이것이 좋은 생각이 아니라고 생각합니다. 범위를 벗어난 인덱스를 적용하지 않는 견고한 코드를 작성하는 것이 좋습니다.

반환하여 이러한 오류가 자동으로 실패하면 (위의 코드에서 제안한대로) nil훨씬 더 복잡하고 다루기 어려운 오류가 발생하기 쉽습니다.

사용하는 것과 비슷한 방식으로 재정의를 수행하고 자신 만의 방식으로 아래 첨자를 작성할 수 있습니다. 단점은 기존 코드가 호환되지 않는다는 것입니다. 제네릭 x [i] (C에서와 같이 텍스트 전처리 기가없는)를 재정의하는 후크를 찾는 것이 어려울 것으로 생각합니다.

내가 생각할 수있는 가장 가까운 것은

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

편집 : 이것은 실제로 작동합니다. 짧막 한 농담!!

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
동의하지 않을 것입니다-선택적 바인딩의 요점은 조건이 충족되는 경우에만 성공한다는 것입니다. (선택 사항 인 경우 값이 있음을 의미합니다.) if let이 경우에는 프로그램을 더 복잡하게 만들거나 오류를 다루기 어렵게 만들지 않습니다. 단순히 기존의 두 문장 if경계 검사 및 실제 조회를 한 줄로 요약 된 요약문으로 요약합니다. 인덱스가 요구처럼, 아웃 오브 바운드되는 것이 정상입니다 (특히 UI에서 작업)의 경우가 있습니다 NSTableView에 대한을 selectedRow선택하지 않고는.
Craig Otis

3
@ 문디 (Mundi) 이것은 OP의 질문에 대한 답변이 아닌 의견 인 것 같습니다.
jlehr

1
@CraigOtis 동의하지 않습니다. 이 검사 는 언어가 배열 첨자 작성을 정의하는 방식이 아닌 "예를 들어 OP를 사용 하거나 사용하여"한 줄로 요약 된 문장 "으로 간결하게 작성할 수 있습니다 . countElementscount
Mundi

1
@jlehr 어쩌면 그렇지 않습니다. 제기 된 문제의 의도 나 지혜에 의문을 갖는 것은 공정한 게임입니다.
Mundi

2
@Mundi Heh, 특히 나중에 질문에 실제로 답변하도록 편집하는 경우 특히 그렇습니다. :-)
jlehr

1

nil유스 케이스에서 s로 배열을 채 웠습니다 .

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
}

또한 safe:Erica Sadun / Mike Ash의 레이블이 있는 아래 첨자 확장명을 확인하십시오 .


0

Swift에 대한 "일반적으로 거부 된 변경 사항"목록에는 충돌이 아닌 옵션을 반환하기 위해 Array 첨자 액세스를 변경하는 내용이 포함되어 있습니다 .

확인 Array<T>첨자 액세스 반환 T?또는 T!대신을 T: 현재 배열의 행동이 의도적 정확하게 범위를 벗어날 배열 액세스는 논리 오류라는 사실을 반영으로. 현재 동작을 변경하면 Array허용되지 않는 수준으로 액세스 가 느려집니다 . 이 주제는 이전에 여러 번 나타 났지만 받아들이지 않을 것입니다.

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

따라서 기본 첨자 액세스는 선택 사항을 반환하도록 변경되지 않습니다.

그러나 Swift 팀 / 커뮤니티는 함수 또는 아래 첨자를 통해 배열에 새로운 선택적 반환 액세스 패턴을 추가 할 수 있습니다.

이것은 Swift Evolution 포럼에서 제안되고 논의되었습니다.

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

특히 Chris Lattner는이 아이디어에 "+1"을 부여했습니다.

이에 대해 가장 자주 제안되는 철자는 다음과 같습니다. yourArray[safe: idx] 과 같습니다. 이것을 추가하면 +1입니다.

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

따라서 일부 Swift 버전에서는 즉시 사용할 수 있습니다. Swift Evolution 스레드에 기여하기를 원하는 사람에게 권장합니다.


0

작업이 실패한 이유를 전파하려면 오류가 옵션보다 낫습니다. 아래 첨자는 오류를 던질 수 없으므로 방법이되어야합니다.

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

왜 아무도 모름

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
        }
    }
}

사용법은 쉽고 스위프트 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")]

참고 : 신속하게 배열을 성장시킬 때 성능 시간 (시간 / 공간 모두)을 이해해야하지만 작은 문제의 경우 Swift를 사용하여 Swifting 자체를 중단해야합니다


-1

배열에 대한 간단한 확장을 만들었습니다.

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
        }
    }

}

그것은 설계된대로 완벽하게 작동합니다

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

-1

스위프트 5 사용법

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

로 결국하지만 정말 일반적으로처럼하고 싶었다

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

그러나 컬렉션이 상황에 따라 적절하다고 생각합니다.


이 답변은 허용되는 답변과 어떻게 다릅니 까? 나에게는 정확히 똑같아 보입니다 (중복).
Legonaftik

-1

배열에서 값 을 가져와야 할 때 작은 성능 저하 (예 : 컬렉션이 크지 않은 경우)를 신경 쓰지 않으면 사전에 포함되지 않은 사전 기반 대안이 있습니다. 맛) 컬렉션 확장 :

// Assuming you have a collection named array:
let safeArray = Dictionary(uniqueKeysWithValues: zip(0..., array))
let value = safeArray[index] ?? defaultValue;
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.