演習: Logger トレイト

log メソッドを持つトレイト Logger を使って、シンプルなロギングユーティリティを設計してみましょう。進行状況をログに出力する可能性があるコードは、&impl Logger を受け取れるようになります。テストでは、これによってメッセージをテストのログファイルに出力できます。一方、本番ビルドでは、メッセージをログサーバーに送信できます。

ただし、以下で与えられている StderrLogger は、冗長性に関係なくすべてのメッセージをログに出力します。あなたの課題は、最大冗長性を超えるメッセージを無視する VerbosityFilter 型を書くことです。

これは一般的なパターンです。つまり、トレイト実装をラップする構造体が、その同じトレイトを実装し、その過程で振る舞いを追加するというものです。「Generics」セグメントでは、ラッパーをラップ対象の型に対してジェネリックにする方法を見ていきます。

// Copyright 2023 Google LLC
// SPDX-License-Identifier: Apache-2.0

trait Logger {
    /// Log a message at the given verbosity level.
    fn log(&self, verbosity: u8, message: &str);
}

struct StderrLogger;

impl Logger for StderrLogger {
    fn log(&self, verbosity: u8, message: &str) {
        eprintln!("verbosity={verbosity}: {message}");
    }
}

/// Only log messages up to the given verbosity level.
struct VerbosityFilter {
    max_verbosity: u8,
    inner: StderrLogger,
}

// TODO: `VerbosityFilter` に `Logger` トレイトを実装する。

fn main() {
    let logger = VerbosityFilter { max_verbosity: 3, inner: StderrLogger };
    logger.log(5, "FYI");
    logger.log(2, "Uhoh");
}