Как я могу создать индекс с помощью getter, который возвращает необязательный, но setter, который возвращает необязательный - PullRequest
0 голосов
/ 27 октября 2018

Я пишу собственную коллекцию под названием TriangularArray<T>.Он представляет собой такую ​​структуру:

     x
    x x
   x x x
  x x x x
 x x x x x

, где каждый x является элементом в массиве.Я могу получить доступ к элементам с номером строки и номером индекса, оба начинаются с нуля.Например, доступ к (4, 2) из ​​следующего:

     a
    b c
   d e f
  g h i j
 k l m n o

приведет к m (5-я строка, третье значение в этой строке).

Я использовал [[T]] в качестве резервного массива, и я написал нижний индекс следующим образом:

subscript(_ row: Int, _ index: Int) -> T? {
    get {
        // innerArray is the [[T]] used for backing
        if row < 0 || row >= innerArray.count {
            return nil
        }
        if index < 0 || index > row {
            return nil
        }
        return innerArray[row][index]
    }

    set {
        if row < 0 || row >= innerArray.count {
            return
        }
        if index < 0 || index > row {
            return
        }
        innerArray[row][index] = newValue!
    }
}

Логика заключается в том, что нижний индекс вернет nil, если вы получите доступ к несуществующей строке и индексу, например (1, 3),Однако, возвращая индекс T?, newValue в установщике также становится необязательным, и я вынужден принудительно развернуть его.

Я действительно хочу проверить во время компиляции такие вещи:

triangularArray[0, 0] = nil // this should be a compile time error

Я пытался найти это в Google, но нашел только этот вопрос , который очень устарел.Конечно, мы можем добиться большего успеха в Swift 4.2, верно?

Ответы [ 2 ]

0 голосов
/ 09 ноября 2018

К сожалению, это невозможно сделать со Swift (и другими языками, работающими с динамическими массивами) по той причине, что размер массива является динамическим и неизвестен во время компиляции (его можно инициализировать любым значением, когда программа бег).
Например, если TriangularArray<T> имеет размер 1, то [0, 0] является допустимым элементом , и компилятор не может знать об этом заранее.
В стандартной библиотеке нет ошибки времени компиляции при попытке доступа к массиву типа array[-1] - это всегда будет компилироваться, но всегда приведет к ошибке времени выполнения.

Я думаю, что решение, которое вы используете в настоящее время с использованием опций, кажется лучшим здесь. Вы также согласны с тем, как работает Array, и запускаете fatalError, если указаны недействительные подписки.
В качестве альтернативы можно создать пользовательскую структуру Index внутри TriangularArray, которая представляет индексы треугольника и может быть дополнительно построена из значений x и y (хотя это может немного усложнить ситуацию).

PS: В этом ответе предполагается, что TriangularArray<T> может иметь треугольник произвольной высоты (высота, которая может быть указана во время выполнения), так как она не указана в вопросе. Если высота определяется во время компиляции, то границы могут быть жестко закодированы и, как @Raul Mantilla, упомянутый #error, могут использоваться.

0 голосов
/ 08 ноября 2018

Только Swift 4.2 может помочь вам отмечать такие проблемы в нашем коде, я не думаю, что это возможно с 4.1 или менее.

Swift 4.2 пример:

#if true
   #error("add here your compiler error")
#endif
...