🔥 중첩된 하위 명령어 정의하기

294자
3분

다음은 Math 세 번째 하위 명령어인 Statistics를 정의해 볼게요. Statistics 명령어는 설정에서 사용자 정의 명령어 이름(stats)을 지정해 타입 이름에서 파생된 기본값(statistics)을 재정의해요. 그리고 추가로 하위 명령어 두 개를 선언하고 있는데, 이는 마치 나무에서 가지가 갈라지듯이, 명령어의 구조가 세분화된다는 것을 의미합니다.

extension Math {
    struct Statistics: ParsableCommand {
        static var configuration = CommandConfiguration(
            commandName: "stats",
            abstract: "Calculate descriptive statistics.",
            subcommands: [Average.self, StandardDeviation.self])
    }
}
 
swift

마지막으로 AverageStandardDeviation 타입으로 하위 명령어를 완성해 볼게요. 각 하위 명령어는 약간 다른 인자를 가지고 있어서 위에서 정의한 Options 타입을 사용하지 않아요. 결국 각 하위 명령어는 독립적이며 공유 인자와 고유 인자를 조합해 사용할 수 있어요.

extension Math.Statistics {
    struct Average: ParsableCommand {
        static var configuration = CommandConfiguration(
            abstract: "Print the average of the values.")
 
        enum Kind: String, ExpressibleByArgument {
            case mean, median, mode
        }
 
        @Option(help: "The kind of average to provide.")
        var kind: Kind = .mean
 
        @Argument(help: "A group of floating-point values to operate on.")
        var values: [Double] = []
 
        func calculateMean() -> Double { ... }
        func calculateMedian() -> Double { ... }
        func calculateMode() -> [Double] { ... }
 
        mutating func run() {
            switch kind {
            case .mean:
                print(calculateMean())
            case .median:
                print(calculateMedian())
            case .mode:
                let result = calculateMode()
                    .map(String.init(describing:))
                    .joined(separator: " ")
                print(result)
            }
        }
    }
 
    struct StandardDeviation: ParsableCommand {
        static var configuration = CommandConfiguration(
            commandName: "stdev",
            abstract: "Print the standard deviation of the values.")
 
        @Argument(help: "A group of floating-point values to operate on.")
        var values: [Double] = []
 
        mutating func run() {
            if values.isEmpty {
                print(0.0)
            } else {
                let sum = values.reduce(0, +)
                let mean = sum / Double(values.count)
                let squaredErrors = values
                    .map { $0 - mean }
                    .map { $0 * $0 }
                let variance = squaredErrors.reduce(0, +) / Double(values.count)
                let result = variance.squareRoot()
                print(result)
            }
        }
    }
}
 
swift