Подтвердить что ты не робот

Есть ли причина, по которой массив [index] не возвращает необязательный?

Мне кажется, что array[index] должен возвращать необязательный, учитывая, что индекс может быть вне границ.

Это позволит использовать код, например:

if let object = array[index] {
  // Do stuff
}

Это легко сделать с помощью метода расширения, но зная реальную причину, почему это так, было бы полезно знать.

4b9b3361

Ответ 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?
}