🔥 AsyncParsableCommand

386자
4분

AsyncParsableCommand는 비동기로 실행할 수 있는 명령 타입입니다. 중첩된 명령 트리 일부로 작동해요. 아래 코드는 AsyncParsableCommand 프로토콜을 정의하고 있습니다.

swift
protocol AsyncParsableCommand : ParsableCommand
 
swift
protocol AsyncParsableCommand : ParsableCommand
 

명령 run() 메서드 구현에서 async/await 코드를 사용하려면 다음 단계를 따르세요:

  1. 커맨드 라인 도구 루트 명령에 AsyncParsableCommand를 따르도록 선언하세요. 해당 명령이 비동기 코드를 사용하는지 여부는 상관없습니다.
  2. 루트 명령에 @main 속성을 적용하세요. (참고: 루트 명령이 main.swift 파일에 있다면 파일 이름을 명령 이름으로 바꾸세요.)
  3. 비동기 코드를 사용해야 하는 모든 명령에 AsyncParsableCommand를 따르도록 선언하고 run() 메서드를 async로 표시하세요. 비동기 코드를 사용하지 않는 하위 명령은 변경이 필요 없습니다.

다음 예제는 Foundation 비동기 FileHandle.AsyncBytes를 사용해 파일에서 줄 수를 세는 CountLines 명령을 선언합니다. 여기서 CountLines는 커맨드 라인 도구 루트 명령입니다:

swift
import Foundation
import ArgumentParser
 
struct CountLines: AsyncParsableCommand {
    @Argument(transform: URL.init(fileURLWithPath:))
    var inputFile: URL
 
    mutating func run() async throws {
        let fileHandle = try FileHandle(forReadingFrom: inputFile)
        let lineCount = try await fileHandle.bytes.lines.reduce(into: 0)
            { count, _ in count += 1 }
        print(lineCount)
    }
}
 
swift
import Foundation
import ArgumentParser
 
struct CountLines: AsyncParsableCommand {
    @Argument(transform: URL.init(fileURLWithPath:))
    var inputFile: URL
 
    mutating func run() async throws {
        let fileHandle = try FileHandle(forReadingFrom: inputFile)
        let lineCount = try await fileHandle.bytes.lines.reduce(into: 0)
            { count, _ in count += 1 }
        print(lineCount)
    }
}
 

코드 설명:

  • import Foundation: Foundation 프레임워크를 가져옵니다.
  • struct CountLines: AsyncParsableCommand: CountLines 구조체를 선언하고 AsyncParsableCommand 프로토콜을 따릅니다.
  • @Argument(transform: URL.init(fileURLWithPath:)): 명령줄 인수로 받은 파일 경로를 URL로 변환합니다.
  • var inputFile: URL: 입력 파일 URL을 저장할 프로퍼티입니다.
  • mutating func run() async throws: 비동기로 실행되는 run() 메서드를 선언합니다.
  • let fileHandle = try FileHandle(forReadingFrom: inputFile): 입력 파일을 읽기 위한 FileHandle을 생성합니다.
  • let lineCount = try await fileHandle.bytes.lines.reduce(into: 0) { count, _ in count += 1 }: 파일 각 줄을 비동기로 읽어 줄 수를 계산합니다.
  • print(lineCount): 줄 수를 출력합니다.

Swift 5.5에서 사용

Swift 5.5에서는 비동기 @main 진입점으로 별도 독립형 타입을 선언해야 합니다. 아래 코드 스니펫처럼 AsyncMainProtocol을 따르는 구조체를 선언하고 typealias Command를 루트 명령으로 지정하세요.

swift
@main struct AsyncMain: AsyncMainProtocol {
    typealias Command = <#RootCommand#>
}
 
swift
@main struct AsyncMain: AsyncMainProtocol {
    typealias Command = <#RootCommand#>
}
 

여기서 <#RootCommand#>를 실제 루트 명령 이름으로 변경합니다. 위 예제에서는 CountLines가 루트 명령이므로 다음과 같이 작성할 수 있습니다:

swift
@main struct AsyncMain: AsyncMainProtocol {
    typealias Command = CountLines
}
 
swift
@main struct AsyncMain: AsyncMainProtocol {
    typealias Command = CountLines
}
 

그리고 CountLines 명령을 구현합니다:

swift
import Foundation
 
struct CountLines: AsyncParsableCommand {
    @Argument(transform: URL.init(fileURLWithPath:))
    var inputFile: URL
 
    mutating func run() async throws {
        let fileHandle = try FileHandle(forReadingFrom: inputFile)
        let lineCount = try await fileHandle.bytes.lines.reduce(into: 0)
            { count, _ in count += 1 }
        print(lineCount)
    }
}
 
swift
import Foundation
 
struct CountLines: AsyncParsableCommand {
    @Argument(transform: URL.init(fileURLWithPath:))
    var inputFile: URL
 
    mutating func run() async throws {
        let fileHandle = try FileHandle(forReadingFrom: inputFile)
        let lineCount = try await fileHandle.bytes.lines.reduce(into: 0)
            { count, _ in count += 1 }
        print(lineCount)
    }
}
 

이렇게 하면 AsyncParsableCommand를 사용해 커맨드 라인 도구에 비동기 코드를 쉽게 통합할 수 있습니다. 그리고 명령 run() 메서드에서 async/await을 활용하면 다양한 비동기 작업을 수행할 수 있습니다.

YouTube 영상

채널 보기
NestJS 커스텀 데코레이터 인자 전달 및 파이프 검증 활용법 | NestJS 가이드
NestJS 커스텀 데코레이터, createParamDecorator 사용 | NestJS 가이드
Writer 펑터와 클라이슬리 카테고리 | 프로그래머를 위한 카테고리 이론
class-validator 와 DTO | NestJS 가이드
인터셉터와 RxJS로 캐시 시스템 구축하기 | NestJS 가이드
NestJS 인터셉터에서 map 연산자로 응답을 변환하는 방법 | NestJS 가이드
존 매카시가 들려주는 인공지능의 탄생 이야기
함수 객체의 보편적 구성 | 프로그래머를 위한 카테고리 이론