我正在使用ArgumentParser包进行命令行解析,并希望将其与Swift并发性的async API一起使用:

struct Foo: ParsableCommand {
    @Argument(
        help: "File to be parsed. If not present, parses stdin.",
        transform: URL.init(fileURLWithPath:)
    )
    var file: URL?

    mutating func run() async throws {
        let handle: FileHandle
        if let file {
            handle = try .init(forReadingFrom: file)
        } else {
            handle = .standardInput
        }

        for try await line in handle.bytes.lines {
            // do something with each line
        }

        try handle.close()
    }
}

但是当我这样做的时候,我总是看到"用法"文本:

USAGE: foo [<file>]

ARGUMENTS:
  <file>                  File to be parsed. If not present, parses stdin.

OPTIONS:
  -h, --help              Show help information.

我没有收到任何编译错误,但无论我是否提供参数,我都会看到"Usage"文本.

推荐答案

问题是ParsableCommandrun() async throws一起使用.

AsyncParsableCommand代替.正如它的documentation所说的那样:

要在命令的run()方法实现中使用async/await代码,请执行以下步骤:

  1. 对于命令行工具中的根命令,无论该命令是否使用异步代码,都应声明符合AsyncParsableCommand.
  2. @main属性应用于根命令.(注意:如果根命令位于main.Swift文件中,请将该文件重命名为该命令的名称.)
  3. 对于需要使用异步代码的任何命令,声明符合AsyncParsableCommand,并将run()方法标记为async.不需要对不使用异步代码的子命令进行更改.

不幸的是,虽然更广泛的documentation偶尔会提到支持async,但您必须深入研究代码样例(具体地说,count-lines),或者倾注整个类库才能偶然发现AsyncParsableCommand.

因此,使用AsyncParsableCommand,async格式副本为run:

import ArgumentParser

@main
struct Foo: AsyncParsableCommand {
    @Argument(
        help: "File to be parsed. If not present, parses stdin.",
        transform: URL.init(fileURLWithPath:)
    )
    var file: URL?

    mutating func run() async throws {
        let handle: FileHandle
        if let file {
            handle = try .init(forReadingFrom: file)
        } else {
            handle = .standardInput
        }

        for try await line in handle.bytes.lines {
            // do something with each line
        }

        try handle.close()
    }
}

但是,不幸的是,如果您意外地使用了runParsableCommandasync格式副本,它编译时不会出错,但在您运行它时只会生成"Usage"文本,而没有关于why它不工作的任何诊断信息.

简而言之,ParsableCommand需要run的非async格式.async的再现需要AsyncParsableCommand个.

Swift相关问答推荐

在Swift中initt()完成后运行一个函数

是否有一个Kotlin等价的Swift s @ AddendableReport注释'

纹理资源加载问题(图像解码失败)

为什么第二项任务不在第一项任务完成之前开始?(并发队列)

SwiftData:线程1:&Quot;NSFetchRequest找不到实体名称';提醒&q;的NSEntityDescription

SWIFT闭包使用的是陈旧的值,即使它是S@转义

MacOS 13-如何使用SwiftUI创建Message.App设置工具栏?

Swift 扩展:通过方法重载增强现有类

DispatchQueue.main.asyncAfter 等同于 Swift 中的 struct 化并发?

将弱引用作为类函数引用传递时,弱引用无法按预期工作

将 Encodable 扩展添加到 Swift 嵌套枚举

使用 RxSwift 围绕 async/await 方法创建 Observable

如何自己实现同一个 iOS 16 锁屏圆形小部件?

如何使 SwiftUI Picker 换行文本

Xcode:方法参数的代码完成

Swift 读写图片占用大量内存

UnkeyedEncodingContainer 和 KeyedEncodingContainerProtocol 中的 superEncoder 是什么?

如何使用 Swift/iOS 为人类书写的笔画制作动画?

如何在 iOS Swift 中进行多线程、并发或并行?

Swift 的 JSONDecoder 在 JSON 字符串中有多种日期格式?