#swift #optional
#swift #тип параметра
Вопрос:
Что я обнаружил
Этот вопрос касается чего-то, что я заметил немного странным в Swift
языке. Я столкнулся с этим поведением, поскольку это была ошибка в моем коде.
Если я создал массив для сетки как неявно развернутый необязательный элемент, то map
ведет себя странно. Взгляните на этот код:
let grid: [[Int]]! = [ // May be defined like this if set later on
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
print(grid.map { $0[0] }!)
// Prints "[1, 2, 3]" (not what I wanted)
print(grid!.map { $0[0] })
// Prints "[1, 4, 7]" (what I wanted)
Я знаю, что строку можно получить, просто выполнив grid[0]
. Тем не менее, я пытаюсь получить столбец.
Я попробовал первый метод, описанный выше, который выдает только строку вместо столбца. Второй метод сработал и выдал столбец.
В чем причина?
Я определил grid
как [[Int]]!
, что является неявно развернутым необязательным.
- Почему мне нужно заставить unwrap
grid
правильно использоватьmap
? - Почему первый метод действует так же, как возврат строки с помощью
grid[0]
?
Комментарии:
1. Должно ли это быть
[[Int]]!
вместо[[Int]]
?2. @AhmadF Это определяется как
[[Int]]!
. Это связано с тем, что, как говорится в комментарии, оно может быть установлено позже. Оно могло быть объявлено какvar grid: [[Int]]!
, а затем установлено позже.3. Помимо вашего основного вопроса, я предлагаю вам выделить этот шаблон «настраиваемый, но только один раз» в отдельный тип, чтобы вы могли «убрать» необязательность, forums.swift.org/t /…
4. @Alexander Я, честно говоря, не думаю, что для этого стоит использовать дополнительный код. Я буду придерживаться just
var
, это намного аккуратнее.5. @George_E Это зависит от того, как часто вы это делаете. Как правило, шаблон «установить обязательный набор хотя бы один раз» довольно распространен. При 2 вариантах использования я бы рассмотрел это, при 3 я бы настоятельно рекомендовал это. Строки кода не определяют сложность. В большинстве случаев «более простое» решение на самом деле длиннее, потому что оно хорошо справляется с абстрагированием деталей.
Ответ №1:
Существует две версии map
: одна, которая работает с массивом, и другая, которая работает с опциями.
Ваш grid
является необязательным, и хотя это неявно развернутый необязательный параметр (IUO), он все еще является необязательным. SWIFT будет лечить ИУО как необязательно всякий раз, когда это возможно, и только силой разворачивает значение для развернутого типа не требуется.
Из-за этого вместо ожидаемой используется необязательная версия map
. Явно разворачивая grid
с !
помощью, вы затем разрешаете использовать желаемую версию map
.
Как map
работает с необязательным?
Когда карта применяется к необязательному объекту, она применяет закрытие к развернутому значению. Если необязательным является nil
, ничего не происходит.
Итак, grid
разворачивается и становится $0
, и закрытие возвращает $0[0]
, которое является первой строкой grid
.
Примечание: В Xcode, если вы optionнажмете map
на каждое утверждение, вы увидите, что первое говорит:
Оценивает данное закрытие, когда этот необязательный экземпляр не равен нулю, передавая развернутое значение в качестве параметра.
и второй:
Возвращает массив, содержащий результаты сопоставления данного замыкания по элементам последовательности.
Комментарии:
1. Пожалуйста. Я думаю, что разработчики Swift могли бы избежать этой путаницы, назвав
map
, который работает с опциями, чем-то другим.2. Да, мне потребовалась целая вечность, чтобы выяснить ошибку, поскольку я делал решатель судоку. Он проверял только строки, так как столбцы не проверялись 😛 Его следует переименовать в
mapOpt
или что-то в этом роде.3. Я думаю, что оно названо
map
потому, что и optional, и array являются функторами, иmap
это общее название для функторов в функциональных языках ( en.wikipedia.org/wiki/Functor_ (functional_programming) )