Я пишу собственный сборник под названием 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, не так ли?
@MartinR Понятно. Может быть, я смогу использовать какую-нибудь другую языковую функцию для достижения подобной эстетики и в то же время запретить nil ...
Единственное, что приходит мне в голову, - это определить два метода индексации: один для получения / установки необязательного значения, а другой индекс только для получения, возвращающий необязательное значение (например, «безопасный метод доступа к массиву», обсуждаемый в настоящее время на forum.swift.org/t/add-accessor-with-bounds-check-to-array/…)
В самом деле, стандартная библиотека обрабатывает это, делая такие дополнительные возвращающие средства доступа доступными только для получения, например свойства (Bidirectional)Collectionfirst и last.
Другой вариант (также из обсуждения на форуме Swift) - определить метод доступа elementAt(row:index:) -> T?. Другой вопрос, действительно ли вы хотите, чтобы сеттер игнорировал недействительные индексы без уведомления, или это должно привести к сбою.
С помощью этого кода вы не можете добавить новый линии в innerArray. Это желаемое поведение?
@ Carpsen90 в коллекции всегда будет фиксированное количество строк, так что да.





Только Swift 4.2 может помочь вам отметить такие проблемы в нашем коде, я не думаю, что это возможно с 4.1 или ниже.
Пример Swift 4.2:
#if true
#error("add here your compiler error")
#endif
К сожалению, это невозможно сделать со Swift (и другими языками, работающими с динамическими массивами) по той причине, что размер массива является динамическим и не известен во время компиляции (он может быть инициализирован любым значением во время работы программы).
Например, если TriangularArray<T> имеет размер 1, то [0, 0]является допустимым элементом, и компилятор не может знать это заранее.
В стандартной библиотеке нет ошибки времени компиляции, когда вы пытаетесь получить доступ к массиву, подобному array[-1] - это всегда будет компилироваться, но всегда будет приводить к ошибке времени выполнения.
Я думаю, что решение, которое у вас есть в настоящее время с использованием дополнительных опций, кажется здесь лучшим сценарием. Вы также должны быть последовательны в том, как работает Array, и запускать fatalError, если указаны недопустимые индексы.
Альтернативой было бы создание пользовательской структуры Index в TriangularArray, которая представляет индексы треугольника и может быть дополнительно построена из значений x и y (хотя это может немного усложнить ситуацию).
PS: Этот ответ предполагает, что TriangularArray<T> может иметь треугольник произвольной высоты (высоту, которую можно указать во время выполнения), поскольку это не указано в вопросе. Если высота определяется во время компиляции, тогда границы могут быть жестко закодированы и, как упомянул @Raul Mantilla, можно использовать #error.
Не думаю, что ситуация изменилась. Геттеры / сеттеры подстрочного индекса по-прежнему возвращают / принимают тот же тип.