#swift
#быстрый #swift
Вопрос:
Этот код работает нормально. Он повторяет мой массив из единицы Int!
и выводит его величину.
import Foundation
let x : Int! = 1
[x].forEach {i in
print(i.magnitude)
}
Вывод:
1
Предположительно, i
в теле цикла есть Int
или Int!
, и действительно, если я попрошу Xcode предоставить «быструю справку» по forEach
его отчетам:
func forEach(_ body: (Int) throws -> Void) rethrows
Однако, если выполнить два оператора в моем forEach
теле, вместо этого он не сможет скомпилироваться, жалуясь, что мне нужно развернуть, i
который теперь имеет необязательный тип Int?
.
import Foundation
let x : Int! = 1
[x].forEach {i in
print(i.magnitude)
print(i.magnitude)
}
Ошибка компиляции:
Value of optional type 'Int?' must be unwrapped to refer to member 'magnitude' of wrapped base type 'Int'
И если я попрошу «быструю помощь» сейчас, я получу:
func forEach(_ body: (Int?) throws -> Void) rethrows
Каким образом, черт возьми, количество операторов, которые я помещаю в тело моего цикла, влияет на тип переменной цикла?
Комментарии:
1. Вывод типа плюс неявная необязательность не распространяются. Это всего лишь цена, которую мы платим за то, как опции внедряются в язык. Вы можете исправить это с помощью явного ввода.
2. Компилятор имеет быстрый путь для замыканий с одним выражением. Замыкания с несколькими выражениями не выигрывают от этого и нуждаются в явной аннотации типа. То, что вы видите здесь, — это компилятор, пытающийся определить типы.
Ответ №1:
По сути, вы выявили крайний случай крайнего случая. Вы объединили две вещи, которые являются работой дьявола:
- Неявно развернутые опции
- Неявный вывод типа замыканий, наряду с тем фактом, что
- Вывод неявного типа замыканий работает по-другому, когда замыкание состоит из одной строки (именно здесь возникает вопрос «Как, черт возьми, количество операторов»)
Вы должны попытаться избежать обоих из них; ваш код будет чище и будет компилироваться намного быстрее. Действительно, неявный вывод типа чего-либо, кроме одного литерала, такого как string, Int или Double, сильно затягивает время компиляции.
Я не буду притворяться, что имитирую рассуждения компилятора; Я просто покажу вам реальное решение (кроме того, что я вообще не использую IUO).:
[x].forEach {(i:Int) in
print(i.magnitude)
print(i.magnitude)
}
Наш Int
тип является законным, потому что мы используем единственную карточку «выйти из тюрьмы бесплатно», в которой говорится, что неявно развернутый необязательный вариант может быть использован непосредственно там, где ожидается сам развернутый тип. И, явно указывая тип, мы устраняем сомнения компилятора.
(Я говорю «напрямую», потому что неявная развернутость необязательного не распространяется через передачу и присвоение. Вот почему во втором примере вы обнаружили, что Int?
не Int
передается в закрытие.)
Комментарии:
1. Возможно, вас заинтересует мой запрос на bugs.swift.org/browse/SR-13107 которое, если вы правильно об этом подумаете, на самом деле связано с этой ситуацией.
2. Отличный ответ! Чтобы кое-что прояснить: в версии этого кода, не являющейся примером, массив представляет собой раскадровку
IBOutlets
(которую xcode создает как неявно развернутые опции по достаточно разумным причинам). Это не позволяет мне избегать вашего первого пункта!3. Любопытно:
{ (i:Int) in ... }
подразумевает ли это-> Void
(как это происходит с такими простыми функциями, какfunc f() { ... }
), или это оставляет возвращаемый тип неопределенным и, следовательно, требует вывода?4. @Alexander-RestorateMonica Это известно из объявления
forEach
.5. @JamieCockburn Вопрос о том, должны ли торговые точки быть IUOS, является религиозной войной.