Что делает компилятор Swift с моим типом возвращаемого значения? Это как-то кастинг?

#swift #type-conversion #coercion #type-coercion

#swift #преобразование типов #принуждение #тип-принуждение

Вопрос:

У меня есть метод:

 func allRegions() -> [MappedRegion] {
    return self.items.lazy.compactMap { item in item.valveAny }.flatMap { valve in valve.regions }
}
  

Я был откровенно удивлен, что это сработало. Я здесь делаю ленивые вещи, но, по-видимому, ленивая последовательность, которая превращается в последовательность MappedRegion, будет такой же.

Затем я плохо рассчитал время и изменил функцию для чтения:

 func allRegions() -> [MappedRegion] {
    let startTime = Date()
    let result = self.items.lazy.compactMap { item in item.valveAny }.flatMap { valve in valve.regions }
    self.sumRender  = (Date() - startTime)
    return result
}
  

Но это создало ошибку:

 Cannot convert return expression of type 'LazySequence<FlattenSequence<LazyMapSequence<LazyMapSequence<LazyFilterSequence<LazyMapSequence<LazySequence<[StatusRowItem]>.Elements, ValveAbstract?>>, ValveAbstract>.Elements, [MappedRegion]>>>' (aka 'LazySequence<FlattenSequence<LazyMapSequence<LazyMapSequence<LazyFilterSequence<LazyMapSequence<Array<StatusRowItem>, Optional<ValveAbstract>>>, ValveAbstract>, Array<MappedRegion>>>>') to return type '[MappedRegion]'
  

Поначалу это было неожиданностью. Я обнаружил, что если я указал возвращаемый тип result as [MappedRegion] , все было хорошо (например let result:[MappedRegion] = ... ).

Что здесь происходит? Я понимаю, что исходная однострочная функция выводит тип результата как [MappedRegion] , поэтому я, вероятно, не получаю особых преимуществ от ленивого использования. Но что меня смущает, так это то, что это принудительное преобразование ленивой последовательности в фиксированный массив автоматически напоминает кастинг в C, и я думал, что Swift не выполняет кастинг?

Комментарии:

1. Возможно, компилятор оптимизирует lazy вызов, поскольку он обнаруживает, что он не понадобится.

Ответ №1:

Нет, кастинг не выполняется. Вызываются просто две разные flatMap функции. LazyMapSequence имеет две flatMap(_:) функции (ну, технически четыре, но две устарели).

В вашем первом блоке кода выводится эта функция (потому что эта версия flatMap имеет тип возвращаемого значения, который соответствует allRegions типу возвращаемого значения вашей функции):

 func flatMap<SegmentOfResult>(_ transform: (Element) throws -> SegmentOfResult) rethrows -> [SegmentOfResult.Element] where SegmentOfResult : Sequence
  

И в вашем втором блоке кода эта функция выводится (потому что в вашей локальной переменной нет аннотации типа, которая заставляет ее выбирать указанную выше версию flatMap ):

 func flatMap<SegmentOfResult>(_ transform: @escaping (Element) -> SegmentOfResult) -> LazySequence<FlattenSequence<LazyMapSequence<LazyMapSequence<Base, Element>, SegmentOfResult>>> where SegmentOfResult : Sequence