Есть ли причина, по которой массив [index] не возвращает необязательный?
Мне кажется, что array[index]
должен возвращать необязательный, учитывая, что индекс может быть вне границ.
Это позволит использовать код, например:
if let object = array[index] {
// Do stuff
}
Это легко сделать с помощью метода расширения, но зная реальную причину, почему это так, было бы полезно знать.
Ответы
Ответ 1
Это был один из моих первых радаров Swift, который был закрыт как "Ведет себя правильно". Он также обсуждался в форумах dev. Как отметил Дейв Абрахамс:
Что касается обоснования, то его легко и очень часто иметь статические знания о том, что индекс находится в диапазоне... В этом случае его гораздо лучше установить предварительное условие, что индекс действителен, так что обычные случаи использования не должны синтаксически сидите с неудачей, которая не может произойти. Сравните это с индексацией словаря на клавишах, где обычно неизвестно, находится ли ключ в словаре.
Поскольку я стал более опытным в Swift, я пришел к согласию. Иногда мне кажется, что есть встроенный "безопасный индекс" (например, Майк Эш), но я пришел к согласию, что это не должно быть значение по умолчанию.
По умолчанию это приведет к тому, что массивы очень трудны для работы, а не только из-за требуемого разворота, а потому, что тип индекса больше не будет Int
. Требуется, чтобы subscript(Index)
возвращал Element
(не Element?
). Вот почему индекс словаря не Key
; это DictionaryIndex<Key,Value>
. Для создания специального ArrayIndex
, вероятно, будет много раздражающих побочных эффектов. (Возможно, все это закончится, но сомнительно, стоит ли это.)
Настоящий урок здесь заключается в том, что в любом случае вам следует избегать произвольно подписывающих массивов. Когда это практично, вы должны использовать его как CollectionType
. Это означает, что индексирование выполняется только с индексами, которые вы выбрали (например, с indexOf
или indices
) и решительно поддерживая итерацию (for-in
, map
), а не subscriptip. Используйте xs.first
, а не xs[0]
. Если вы рассматриваете его как коллекцию, а не массив, то вы получаете информацию о безопасности, но при этом оставляете индексы доступными, когда вам нужно решать особые проблемы, когда вы знаете, что индекс находится в зоне действия.
Вот иллюстративный пример. Рассмотрим этот общий цикл, который, по вашему мнению, требует подписи:
let xs = [1,2,3]
for i in 0..<xs.count {
print("\(i): \(xs[i])")
}
Мы можем сделать это немного лучше и не полагаться на наше специальное знание индексации массива и заставить его работать для всех Коллекций:
for i in xs.indices {
print("\(i): \(xs[i])")
}
Но даже это не нужно. Мы можем сделать намного лучше и заставить его работать для всех последовательностей:
for (i, x) in xs.enumerate() {
print("\(i): \(x)")
}
Никакой индекс не требуется.
Ответ 2
Учитывая исчерпывающее обсуждение в user3441734: s ответ (который мы, вероятно, должны были принять в чате...), я чувствую, что должен четко прояснить, насколько я думаю, что пользователь 3441734 пытался сделать.
Прежде всего, обратите внимание, что вопрос охватывает
- В чем причина того, что Swift может привести к тому, что ситуация с недействительным индексом ведет себя так же (исключение исключения из-за пределов) вместо того, чтобы возвращать необязательный?
Ответ Rob является исчерпывающим и охватывает это очень хорошо, но я думаю, что user3441734: s ответ хотя бы заслуживает статуs >= 0, так как он содержит другую причину относительно того, почему гипотетический случай "swift позволяет вернуть неверный индекс необязательный вариант", возможно, не очень хорошая идея. Обратите внимание, что это ни в коем случае "... настоящая причина, почему..." swift не дает недопустимый индекс return nil, но точка, которую я думаю, заслуживает того, чтобы быть >= 0-проголосовали.
Вопрос не затрагивает:
- Можно ли получить необязательный вариант вместо исключения, если индекс за пределами границ.
Сам автор вопроса утверждает: "Это легко сделать с помощью метода расширения".
Итак, с этим в воздухе, давайте взглянем на user3441734: ответьте и попробуем сделать его немного более понятным, что он/она попытался указать нам.
Мы проанализируем следующее выражение в предположении, что мы находимся в параллельном юниверсе Swift, , где ситуации с неверным индексом (wrt-массивы) рассматриваются как опции и возвращают nil
.
// Lets assume the following is all in the scope of some function
var arr: Array<Int?> = []
arr.append(1)
arr.append(nil)
arr.append(3)
print("\(arr)") // Optional(1), nil, Optional(3)
// lets say the function randomIntegerTwoOrFour() -> Int returns,
// randomly, either value 2 or value 4.
let ourMagicAndAtCompileTimeUnknownIndex = randomIntegerTwoOrFour()
// now, in our parallel Swift universe, say we want
// use an if let clause on our array at our magic index
if let n = arr[ourMagicAndAtCompileTimeUnknownIndex] {
// ...
}
else {
// lets say we're note careful here, and think that we've
// entered this clause because of a nil valued member of
// our array. If we try to use our magic index for non-nil
// assigment, how would parallell universe Swift 2 handle this?
// We could of course try some downcasting to infer actual,
// (optional) type ourselves, but this is not very "Swifty"
// w.r.t. if let clauses.
}
// on the other hand, say we want to guard against invalid-index
// in our array, using a guard let clause
guard let n = arr[ourMagicAndAtCompileTimeUnknownIndex] else {
print("Out of bounds!")
// or are we ...? Careful parallel Swift universe programmer!
// Naturally, we could (and should, in parallell Swift 2 universe),
// look closer are what type n is at this point, but this is also
// not very "Swifty" in this context).
return
}
Чтобы обернуть его, это то, что я вывел из user3441734: s ответ, и я думаю, что он заслуживает не меньше и, возможно, не более, чем балл 0, однако, чтобы его не проголосовали.
Ответ 3
Это, вероятно, по дизайну. Так как довольно легко получить количество элементов в массиве, если вы будете перебирать с 0 to count-1
, всегда будет вау. Если array[index]
может возвращать нуль, вам придется разворачивать необязательный каждый раз, когда вы повторяетесь через массив, что было бы болью в заднице:).
Ответ 4
Это зависит от типа элементов массива. Например, если вы определяете свой массив как
var arr:[String?] = Array<String?>(count: 5, repeatedValue: "SomeString")
Тогда array[index]
будет необязательным.
Но по своей сути array[index]
является необязательным значением, потому что доступ к массиву за пределами его границ вызывает исключение, не говоря уже о его значении. Таким образом, вы не будете прочитывать сам элемент.
Ответ 5
попробуйте посмотреть
var arr: Array<Int?> = []
arr.append(1)
arr.append(nil)
arr.count == 2
let n = arr[1] // nil
Думаю, теперь легко понять причину. Несмотря на то, что индекс действительно, вы все равно можете получить nil
Я знаю тип, но
if let n = arr[1] {
// how to see the difference if my index is out of range
// or i receive valid nil value?
}