トラック
/
Swift
Swift
/
演習
/
ログの行
ログの行

ログの行

学習演習

はじめに

取りうる状態が特定の集合に限られているデータをモデル化するとき、たとえば曜日やコンパスの方位、コントローラーのボタンなどを扱う場合、IntやStringのような基本的な型には大きな欠点があります。 整数や文字列を使うと、コードは不正な値(999というステータスコードや、"leftt"のようなタイポなど)を常にチェックしなければなりませんし、人間の読者もその数値が何を表しているのかすぐには分かりません。

Swiftはこの問題を、列挙型(しばしばenumと略されます)で解決します。 列挙型は、関連する名前付きの値の集まりに対して共通の型を定義します。コンパイラーは取りうるすべてのケースを事前に把握しているので、コンパイル時にコードの正確さと網羅性をチェックできます。 列挙型は、メソッドやイニシャライザー、計算プロパティーを持つこともできます。

列挙型の定義

列挙型は、enumキーワードのあとに型名を書き、波括弧の中にケースを並べて定義します。 Swiftの慣習では、型名はUpperCamelCase、各ケースはlowerCamelCaseを使います。

enum NESButton {
    case up
    case down
    case left
    case right
    case a
    case b
    case select
    case start
}

複数のケースをカンマで区切って1行にまとめて定義することもできます。

enum NESButton {
    case up, down, left, right, a, b, select, start
}

列挙型のケースを参照するには、列挙型の型名、ドット(.)、ケース名を書きます。型が判明している場合、またはコンパイラーが推論できる場合は、型名を省略して短いドット構文を使えます。

var lastPressed = NESButton.up

// Swift infers the type, so you can omit the type name:
lastPressed = .down

let konamiCode: [NESButton] = [.up, .up, .down, .down, .left, .right, .left, .right, .b, .a]

メソッドとイニシャライザー

列挙型は、クラスや構造体と同じように、メソッドや独自のイニシャライザーを定義できます。列挙型のメソッドの中で、selfは現在のケースの値を指します。

enum Coin {
    case heads
    case tails

    init(_ value: Int) {
        if value.isMultiple(of: 2) {
            self = .heads
        } else {
            self = .tails
        }
    }

    func flip() -> Coin {
        switch self {
        case .heads: return .tails
        case .tails: return .heads
        }
    }
}

let tails = Coin(13)     // .tails
let heads = Coin(0)      // .heads
let flipped = heads.flip() // .tails

生の値

列挙型のケースには、生の値と呼ばれるデフォルト値をあらかじめ設定できます。 列挙型の生の値は、すべて同じ型(Int、String、Characterなど)でなければなりません。

enum NESButton: Character {
    case up = "⬆️"
    case down = "⬇️"
    case left = "⬅️"
    case right = "➡️"
    case a = "🅰️"
    case b = "🅱️"
    case select = "✅"
    case start = "🚦"
}

print(NESButton.left.rawValue) // Prints "⬅️"

init(rawValue:)を使うと、生の値から列挙型を初期化できます。無効な生の値が渡される可能性があるため、このイニシャライザーはオプショナルを返します。

let upButton = NESButton(rawValue: "⬆️") // Optional(NESButton.up)
let invalid = NESButton(rawValue: "🙄")  // nil

Swiftは、StringとIntの列挙型に対して生の値を自動で割り当てることができます。

  • Stringの列挙型では、各ケースの生の値はデフォルトでそのケース名になります。
  • Intの列挙型では、特に指定しない限り、生の値は0から始まり1ずつ増えていきます。
enum Planet: Int {
    case mercury = 1, venus, earth, mars
}

print(Planet.earth.rawValue) // Prints 3

説明

この演習では、ログ行を処理します。

各ログ行は、次の形式の文字列です:"[<LVL>]: <MESSAGE>"。

ログレベルには次のものがあります。

  • TRC(trace)
  • DBG(debug)
  • INF(info)
  • WRN(warning)
  • ERR(error)
  • FTL(fatal)

必要な機能を実装するには、3つの課題をすべて完了する必要があります。

1. LogLevel enumを作成します

上記のログレベルに対応する6つのケースと、ログレベルが欠けている場合や標準的でないログレベルのためのunknownケースを持つLogLevel enumを定義します。

  • trace
  • debug
  • info
  • warning
  • error
  • fatal
  • unknown

2. ログレベルを解析します

次に、ログ行のログレベルを解析するLogLevelのイニシャライザーを実装します。

LogLevel("[INF]: File deleted")
// Returns LogLevel.info
LogLevel("Something went wrong!")
// Returns LogLevel.unknown

3. ログ行を短い形式に変換します

ログ行のログレベルはかなり冗長です。 ログ行を保存するのに必要なディスク容量を減らすため、次のような短い形式が考案されました。"<ENCODED_LEVEL>:<MESSAGE>"

エンコードされたログレベルは、ログレベルを数値に単純に対応付けたものです。

  • trace - 0
  • debug - 1
  • info - 4
  • warning - 5
  • error - 6
  • fatal - 7
  • unknown - 42

短い形式のログ行をStringとして出力するshortFormat(message: String) -> Stringメソッドを実装します。

let overflow = LogLevel.error
overflow.shortFormat(message: "Stack overflow")
// Returns "6:Stack overflow"
GitHubで編集する リンクは新しいウィンドウまたはタブで開きます
Swift Exercism

ログの行を始める準備はできましたか?

Exercismに登録すれば、35個のコンセプト116個の演習、そして本物の人間によるメンタリングとともに、Swiftを学んでマスターできます。すべて無料です。