Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
858 views
in Technique[技术] by (71.8m points)

swift - "Invalid conversion from throwing function to non-throwing function", trying to store a closure and it can't throw

I'm creating a static site generator in Swift, and am coming up with the API for adding "readers" - which are responsible for converting a raw file, of an extension they support, to a Page instance.

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: "")
    })
  }
}

The problem here is the I get the error Invalid conversion from throwing function of type '(File) throws -> Page' to non-throwing function type '(File) -> Page', which makes sense; nowhere in var convert: (File) -> Page does it say it can throw, but the real problem is, that I can't add that either? So, how does one work with throwing closures, and store those closures as a property? Or can I simply not throw any errors in a closure?

question from:https://stackoverflow.com/questions/65890806/invalid-conversion-from-throwing-function-to-non-throwing-function-trying-to

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Your throws is in the wrong place:

static func markdownReader() throws -> Self {

markdownReader() cannot throw. It just returns a Reader. The throwing, if any is going to happen, will happen in try file.readAsString, which is inside the closure. The throw does not magically somehow filter up out of that closure definition to the place where it is defined!

So basically you have two choices. One is to declare that the closure type can in fact throw:

var convert: (File) throws -> Page

The other is: don't let the throw percolate up out of the closure. Catch it:

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

The problem then is that in the catch block you are still obligated to return a Page (unless you'd like to fatalError at this point, on the grounds that the file can't be read so we may as well die). So you'd have to make up a page with fake content, since you failed to obtain the contents from the File.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...