«Недопустимое преобразование из функции выбрасывания в функцию без выбрасывания», попытка сохранить замыкание, и оно не может выбросить

#swift

#swift

Вопрос:

Я создаю генератор статического сайта в Swift и разрабатываю API для добавления «читателей», которые отвечают за преобразование необработанного файла с расширением, которое они поддерживают, в экземпляр страницы.

 import Files

public struct Reader {
  var supportedExtensions: [String]
  var convert: (File) -> Page
}

public extension Reader {
  static func markdownReader() throws -> Self {
    Reader(supportedExtensions: ["md", "markdown"], convert: { file in
      let contents = try file.readAsString(encodedAs: .utf8)
      return Page(slug: "", title: "", content: contents, html: "")
    })
  }
}
 

Проблема здесь в том, что я получаю ошибку Invalid conversion from throwing function of type '(File) throws -> Page' to non-throwing function type '(File) -> Page' , что имеет смысл; нигде в var convert: (File) -> Page нем не говорится, что он может выбрасывать, но реальная проблема в том, что я тоже не могу это добавить? Итак, как работать с метанием замыканий и сохранять эти замыкания как свойство? Или я могу просто не выдавать никаких ошибок при закрытии?

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

1. Не могли бы вы объяснить, почему вы не можете объявить convert throw? var convert: (File) throws -> Page

2. У меня просто было throws ключевое слово в неправильном месте 😅

Ответ №1:

Вы throws не в том месте:

 static func markdownReader() throws -> Self {
 

markdownReader() невозможно выбросить. Он просто возвращает средство чтения. Выбрасывание, если таковое произойдет, произойдет в try file.readAsString , который находится внутри замыкания. Бросок каким-то волшебным образом не отфильтровывается из этого определения замыкания в то место, где оно определено!

Итак, в основном у вас есть два варианта. Один из них — объявить, что тип замыкания может фактически выбрасывать:

 var convert: (File) throws -> Page
 

Другой: не позволяйте выбросу просачиваться из замыкания. Поймайте это:

 do {
    let contents = try file.readAsString(encodedAs: .utf8)
    return Page(slug: "", title: "", content: contents, html: "")
} catch {
    // ???
}
 

Тогда проблема заключается в том, что в catch блоке вы по-прежнему обязаны возвращать страницу (если вы не хотите fatalError на данный момент, на том основании, что файл не может быть прочитан, поэтому мы можем также умереть). Таким образом, вам придется создать страницу с поддельной content , поскольку вам не удалось получить содержимое из файла.

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

1. Спасибо! Правильное расположение throws ключевого слова было решением 😅

2. Я лично считаю, что второе решение лучше, потому что почему читатель должен указывать, что convert функция должна выбрасывать? Это похоже на то, что хвост виляет собакой. Но если вы довольны, хорошо. 🙂

3.Потому что я не хочу иметь дело с опциями, в основном, и весь стек использует функции выбрасывания. Также вы не говорите convert , что НУЖНО выбрасывать, но это возможно. И это идеально вписывается в остальную часть стека.