プログラマー VTuber 衣亥栖ティオのちょっとした話

Youtubeに投稿したプログラミング学習動画の補足説明をするためのブログです。

プログラマーへの道 #135 の補足説明

こんにちは、プログラマーVTuberの衣亥栖ティオです。 この記事はYouTubeに投稿した動画の補足ブログです。

投稿した動画

今回は以下の動画の補足説明をします。


GitHub のURL

私のGitHubは以下です。
https://github.com/tio-iis

Gist のURL

私のGitst(メモ書きみたいなもの)のURLは以下です。
https://gist.github.com/tio-iis

今回の動画で実装したソースコード

今回の実装は以下です。
https://github.com/tio-iis/memo-server/pull/48/files

現時点でのソースコードは以下です。
https://github.com/tio-iis/memo-server/tree/ae6a4c7408a4e5e1802ae0efd739b2d6c1f73746

補足内容

ログの種類について

動画内の実装ではアクセスログ、インフォログ、エラーログを判別するためにKindという値を追加しました。 ログの種類を判別できるようにしておくと検索する際に便利です。 例えばアクセスログをKindで判別できるようにすると、メモ帳アプリのアクセス数を計測することができます。 ログの種類はログレベルとは別で管理することを推奨します。

Goの埋め込みについて

Goには "埋め込み" という仕組みがあります。 埋め込みはGoにおける実装共有を目的にしたものです。
https://code-graffiti.com/embedded-structs-in-golang/

今回はLog構造体とAccessLog構造体にBaseLog構造体を埋め込むことで、 BaseLog構造体の Datetime, Level, Kind という3つのプロパティをLog構造体とAccessLog構造体で共有しています。
https://github.com/tio-iis/memo-server/pull/48/files#diff-2873f79a86c0d8b3335cd7731b0ecf7dd4301eb19a82ef7a1cba7589b5252261R260

このように、埋め込みは似たデータ構造を持つ構造体の定義を重複させないようにすることができます。 今回は構造体のプロパティの重複を排除するために利用しましたが、 プロパティだけではなく、メソッドも共有可能です。 メソッドの共有については今後説明していきたいと思います。

Goのinterface型について

Goにはinterface型という型があります。 以下の説明の通り、"どんな型でも指定できる" という特殊な型になっています。 https://qiita.com/sh-tatsuno/items/0c32c01eaeaf2d726fdf#interface%E5%9E%8B

利用例としては動画内で触れた通り、json.Marshal() があります。
https://pkg.go.dev/encoding/json@go1.17#Marshal

json.Marshal() は引数に構造体を指定することで、その構造体のデータ構造をそのままJSON文字列に変換してくれる関数です。 そのため、引数にいろいろな構造体を指定できるようにする必要があります。 こういった汎用性の高い関数の引数や戻り値にinterface型が利用されます。

json.Marshal()の他にはlog.Printf()があります。
https://pkg.go.dev/log@go1.17#Printf

log.Printf() は以下のlogパッケージの使い方で紹介した通り、ログの出力するメッセージに変数をセットすることができる関数です。
https://gist.github.com/tio-iis/5b7732f09366b010216092f1f918ecaa

ちなみに、Go 1.18 からはinterface型の代わりにany型というものが導入されています。 これはinterface型のエイリアス(同じ機能を持つけど、名前が違うもの)なので、実質interface型のようなものです。 中長期的にはinterface型がなくなって、any型を利用することになるかもしれませんね。
https://qiita.com/sg0hsmt/items/06449d7ec8382b68d457