テキストベースのフォーマットを再帰的にデコードするためのライブラリです。
主な用途は、外部設定ファイルを使った設定ファイルの再帰的デコードです。
JSON、YAML、TOMLなどのテキストベースの汎用フォーマットが、設定ファイルに良く使われています。
フォーマットに汎用性があるので、
後からのパラメータ追加も容易で、機能追加とともに設定ファイルも大きくなりがちです。
機能が増えることはいいのですが、設定ファイルが大きくなると、利用者にとっては見通しが悪くなります。
このような場合、設定の一部を外部設定ファイルとして切り出せれば、見通しの悪さを軽減できます。
ですが、汎用デコーダは、設定ファイル専用ではないので、外部設定ファイルを想定していません。
そこで、外部設定ファイルへの対応できるように、
汎用デコーダでの再帰的デコードをサポートするのが、
このライブラリのRecursiveRebuild()
です。
親要素をデコードした後、recode.RecursiveRebuild()
を実行すると再帰的なデコードが行われます。
ただ、子孫の要素のデコード方法は、RebuildByType()
メソッドとして定義しておく必要があります。
また、RebuildByType()
メソッドは、
引数の型をrecode.RecursiveRebuild()
の2番目の引数と一致させておく必要もあります。
また、RebuildByType()
メソッドがある同じ型を、上位と子孫の要素に同時指定するのは避けてください。
このようにすると、同じRebuildByType()
メソッドが呼ばれるので、無限ループします。
RecursiveRebuild()
では、以下のような処理を行います。
- 引数が同じ
RebuildByType()
メソッドが存在するフィールド値を探す。- 該当するフィールドがなければ終了する。
RebuildByType()
メソッドを呼び出す。RebuildByType()
メソッドが呼び出されたフィールド値に、1.からの処理を再帰的に実行する。
RecursiveRebuild()
の定義は以下のようになっています。
func RecursiveRebuild[T any](v any, param T) error
RebuildByType()
を定義する、AnyRebuilder
インタフェイスは以下のようになっています。
type AnyRebuilder[T any] interface {
RebuildByType(param T) error
}
2つの定義の両方にあるparam T
の引数に、Goのジェネリックス(generics)の機能を使っていますので、
型を自由に変えられます。
ただし、param T
部分の引数の型を、 RecursiveRebuild()
関数とRebuildByType()
メソッドで、そろえる必要があります。
引数の型が一致してないと、RebuildByType()
が呼び出されなくなります。
Example形式の サンプルプログラムは、以下の処理を行っています。
- testfsディレクトリを
os.DirFS()
でfs.FS化- 例えば、embed.FSでも同じことが出来ます。
- fs.FS経由でファイルを読み取って、再帰的にデコード
このデコードでは以下の処理が再帰的に行われます。
- textfile.jsonをTextTextFile型にデコード
- text.jsonをTextTextFileのTextFileフィールドにデコード
- text.txtの内容をTextFileのTextフィールドに設定