4Kotlinでネスト構造のDSLを実装する方法KotlinDSLネスト構造のDSLとは「ネスト構造のDSL」は正式名称ではなく、便宜的にここだけで名付けているものです。ここでは、以下のような入れ子で構造化されたDSLコードを指すものとします。}}上のHttpリクエストのライブラリの他、HTML構造の出力や(kotlinx.html)、WebフレームワークのRouting(KtorのRouting機能)などにも、このパターンは利用されています。この記事ではこのパターンを実装するための方法について紹介します。最終的なコード現代人は忙しいので、結論のコードをまず先にお見せします。仮に最終的に以下のようなDSLを利用したいとします。}}その場合に必要な定義はこちらです。context.init()}ここで用いられている言語仕様として、普段馴染みが薄いのではないかと思われるものは以下の2つです。receiverまず、これらについて解説します。ご存知の方は読み飛ばしてください。lambda公式ドキュメントの説明はこちらです。以下のようにkotlinではメソッドの最終引数が関数の場合は、その部分を引数括弧の外のブロックとして記述することができます。receiver公式ドキュメントの説明はこちらです。日本語でいうとレシーバ付きラムダと呼ばれるやつです。わかりやすくいうと、拡張関数を引数として渡すパターンです。Kotlinでは以下のように書くと、レシーバ付きラムダと呼ばれる拡張関数lambdaになります。//2段階的に実装しながら理解しようの巻Kotlinの文法の説明も終わったので実装について段階的に説明していきます。lambdaを使えば、ネスト構造自体は以下のように簡単に作れます。}}ところがこれだけだと十分ではありません。ネストした構造内で状態を保持したり、メソッドを利用したりしたいためです。receiverを使います。ポイントは以下2点です。receiver機能を使う具体的には以下のようなコードを書きます。}}コメントアウトしたbodyメソッドをHttpRequestContextに定義してやり、以上の要領でbodyブロック内のContextクラスも同じように作ってやれば、記事の冒頭で説明した最終的なコードができあがります。@DslMarkerについてここまででDSLとして動作はするのですが、以下のようなコードで書けてしまいます。}}HttpリクエストのDSLであれば大した問題にならないのですが、HTML構造を生成するためのDSLのように同じ変数名が出てくる場合などには不便があるかと思います。}}こういった問題は標準ライブラリに用意されている@DSLMarkerというアノテーションを使うと解決できます。詳細は割愛しますが、以下のように@DslMarkerを付与したAnnotationを定義し、それをContextクラスに付与することで期待どおりの変数スコープになります。HttpRequestBodyContext(//.....@DslMarkerアノテーションについてはこちらのQiita記事によくまとまっています終わりにいかがだったでしょうか?DSLでオシャレ実装を書くの楽しいので、是非明日からプロダクションコードにコッソリ入れてみてくださいwちなみに私が作っているkotlin-csvというOSSもDSL使っているので、ご興味ある方はコードを参考にしてみてください。requestStockLike13@doyaaaaakenSaaSスタートアップでサーバサイドKotlinやVue.jsを書いている人。smartroundというベンチャーファイナンス業務を効率化するサービス作ってます。frameworkのKtorのドキュメント日本語翻訳プロジェクトの発起人です。upLoginユーザーは見つかりませんでした。