「Kotinミニマリストチュートリアル」第14章Kotlin DSLの使用

第14章Kotlin DSLの使用

これまでの章で、Kotlin DSLの強力な機能を見てきました。たとえば、Gradleの構成ファイルbuild.gradle(Groovy)、および前述のGradle Script Kotlin(Kotlin)、Anko(Kotlin)などはすべてDSLです。DSLプログラミングスタイルを使用すると、プログラムがよりシンプル、よりクリーン、より直感的で簡潔になることがわかります。もちろん、独自のDSLを作成することもできます。

この章では、KotlinのDSLについて学びましょう。

前の章で、Androidで次のネストされたDSLスタイルコードを使用してXMLスタイルビューファイルを置き換えることを確認しました

        UI {
            // AnkoContext

            verticalLayout {
                padding = dip(30)
                var title = editText {
                    // editText 视图
                    id = R.id.todo_title
                    hintResource = R.string.title_hint
                }

                var content = editText {
                    id = R.id.todo_content
                    height = 400
                    hintResource = R.string.content_hint
                }
                button {
                    // button 视图
                    id = R.id.todo_add
                    textResource = R.string.add_todo
                    textColor = Color.WHITE
                    setBackgroundColor(Color.DKGRAY)
                    onClick { _ -> createTodoFrom(title, content) }
                }
            }
        }

XMLスタイルのDSL(XMLは基本的にDSLです)と比較すると、ネイティブのプログラミング言語(Kotlinなど)を使用したDSLスタイルは、明らかにシンプルで、クリーンで、柔軟性があります。

Kotlin DSLのプログラミングスタイルは何ですか?そして、その背後にある原則は何ですか?以下でまとめて説明します。

DSLとは

DSL(ドメイン固有言語)は、特定の問題ドメインに焦点を当てたコンピューター言語(ドメイン固有言語)を指します。一般的なコンピューター言語(GPL)とは異なり、ドメイン固有の言語は特定のドメインでのみ使用されます。

「ドメイン」は、保険、教育、航空、医療などの特定の業界を具体的に指す場合があります。また、JavaEE、.NET、データベース、サービス、メッセージング、アーキテクチャ、ドメイン駆動型設計などの方法またはテクノロジーを指す場合もあります。DSL言語を開発する目的は、よりエレガントで簡潔な方法で、フィールドで一連の課題に直面する必要があることです。これが可能なのは、この言語がフィールドでの唯一の一連の課題を解決するのに十分であり、それほど多くはなく、まったく適切ではないからです。

たとえば、Webページの表示に使用されるHTML言語。より典型的な例はGradleで、これはAntとMavenに基づいており、GroovyベースのDSLを使用して、従来のXMLの代わりにプロジェクトのビルド構成build.gradleを宣言します。

簡単に言えば、DSLは、特定の問題(制限された表現能力)のソリューションモデルの上位レベルの抽象式(ドメイン言語)であり、理解しやすくします(意味論を理解しやすく、意味論モデルを明確にする)。

DSLは問題解決モデルの単なる外部パッケージであり、このモデルはAPIライブラリまたは完全なフレームワークの場合があります。DSLは、特定のドメインの問題について考えるためのモデル言語を提供します。これにより、問題をより簡単かつ効率的に解決できます。DSLは特定の分野に焦点を当て、シンプルで理解しやすく、最小限ですが完全な機能を備えています。DSLにより、モデルの理解と使用が容易になります。

DSLは内部DSLと外部DSLに分けられます。たとえば、Gradle、Ankoなどはすべて、共通のプログラミング言語(JavaおよびKotlin)を使用して作成した内部DSLです。

内部DSL

内部DSLは、プロジェクトで使用される汎用プログラミング言語(Java、C#、またはRuby)に密接に関連するタイプのDSLを指します。一般的なプログラミング言語に基づいて実装されています。

たとえば、RailsフレームワークはRubyベースのDSLと呼ばれ、Rubyによって開発されたWebアプリケーションを管理します。RailsがDSLと呼ばれる理由の1つは、RailsがRuby言語のいくつかの機能を適用するため、Railsベースのプログラミングが汎用のRubyプログラミングとは異なる見た目になるためです。

Martin FowlerとEric Evansによると、フレームワークAPIまたはライブラリAPIが内部DSLを満たすかどうかの主要な特徴の1つは、滑らかなインターフェイスを備えているかどうかです。このようにして、短いオブジェクト式を使用して、それ以外は長い式を編成し、読みやすくすることができます。

外部DSL

外部DSLは一般プログラミング言語(GPL)に似ていますが、外部DSLは特定の領域により重点を置いています。

外部DSLを作成するプロセスは、汎用プログラミング言語を作成するプロセスに似ており、コンパイルまたは解釈できます。正式な文法があり、明確に定義されたキーワードと式タイプのみを使用できます。コンパイルされたDSLは通常、実行可能プログラムを直接生成しません(ただし、生成します)。

ほとんどの場合、外部DSLはコアアプリケーションの動作環境と互換性のあるリソースに変換できます。または、コアアプリケーションを構築するための汎用プログラミング言語に変換できます。たとえば、Hibernateで使用されるオブジェクトリレーショナルマッピングファイルは、外部DSLによってリソースに変換されたインスタンスです。

ヒント:DSLの詳細な紹介については、「ドメイン固有言語」(Martin Fowler)を参照してください。

KotlinのDSL機能のサポート

多くの現代の言語は、内部DSLを作成するための高度な方法をいくつか提供しています。Kotlinも例外ではありません。

KotlinでDSLを作成するには、通常、次の2つの機能を使用します。

  • 拡張機能、拡張属性
  • レシーバー付きのラムダ式(高次関数)

上記のUI {...}コードの例のように、以下のように簡単に説明します。

関数名 関数の署名 取扱説明書
UI fun Fragment.UI(init:AnkoContext。()-> Unit):AnkoContext android.support.v4.app.Fragmentの拡張関数;入力パラメーターinitはレシーバーを含む関数リテラルであり、直接渡すのはLambda式です
verticalLayout インラインfun ViewManager.verticalLayout(init:_LinearLayout。()-> Unit):LinearLayout android.view.ViewManager拡張関数

kotlinx.html DSLを使用してフロントエンドコードを作成する

Kotlin DSLの実用性の理解を深めるために、このセクション
ではKotlinのHTML に関する別のDSL を紹介します。kotlinx.htmlです。

kotlinx.htmlは、WebアプリケーションでHTMLを構築するために使用できるDSLです。従来のテンプレートシステム(JSP、FreeMarkerなど)の代替として使用できます。

kotlinx.htmlは、kotlinx-html-jvmおよびkotlinx-html-jsライブラリのDSLをそれぞれ提供します。これらは、JVMおよびブラウザ(または他のjavascriptエンジン)でKotlinコードを直接使用して、元のHTMLを直接解放するhtmlを構築するために使用されますタブ付きフロントエンドコード。このように、Kotlinを使用して、従来の意味でHTMLページを開始することもできます。Kotlin Webプログラミングはより単純でより純粋になります。

ヒント:kotlinx.htmlの詳細については、Githubアドレスを参照してください:https://github.com/Kotlin/kotlinx.html

kotlinx.htmlを使用するには、まず依存関係を追加します

dependencies {
    def kotlinx_html_version = "0.6.3"
    compile "org.jetbrains.kotlinx:kotlinx-html-jvm:${kotlinx_html_version}"
    compile "org.jetbrains.kotlinx:kotlinx-html-js:${kotlinx_html_version}"
    ...
}

kotlinx.htmlの最新バージョンはhttps://jcenter.bintray.com/ウェアハウスで公開されているので、ウェアハウス構成を追加してみましょう

repositories {
    maven { url 'https://jitpack.io' }
    mavenCentral()
    jcenter() // https://jcenter.bintray.com/ 仓库
    maven { url "https://repo.spring.io/snapshot" }
    maven { url "https://repo.spring.io/milestone" }
}

ミニマリストのBaiduホームページの例を書いてみましょう。このページのフロントエンドHTMLコードは次のとおりです。

<!DOCTYPE html>
<html lang=zh-CN>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name=viewport content="width=device-width,initial-scale=1">
    <title>百度一下</title>
    <link href="https://cdn.bootcss.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
    <link href="dsl.css" rel="stylesheet">
    <script src="dsl.js"></script>
</head>
<body>
<div class="container">
    <div class="ipad center">
        ![](http://upload-images.jianshu.io/upload_images/1233356-49a0fecdc8bfa9cf.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
    </div>

    <form class="form">
        <input id="wd" class="form-control ipad">
        <button id="baiduBtn" type="submit" class="btn btn-primary form-control ipad">百度一下</button>
    </form>
</div>
</body>
</html>

このうち、dsl.cssファイルの内容は以下の通りです

.ipad {
    margin: 10px
}

.center {
    text-align: center;
}

dsl.jsファイルの内容は次のとおりです

$(function () {
    $('#baiduBtn').on('click', function () {
        var wd = $('#wd').val()
        window.open("https://www.baidu.com/s?wd=" + wd)
    })
})

上記では、通常、HTML + JS + CSSを使用してフロントエンドページを記述しています。次に、コードのHTML部分をKotlinのDSL kotlinx.htmlで再実装します。

最初に新しいKotlin + Spring Bootプロジェクトを作成し、次にKotlinビュークラスHelloDSLViewを直接書き込みます。コードは次のとおりです。

package com.easy.kotlin.chapter14_kotlin_dsl.view

import kotlinx.html.*
import kotlinx.html.stream.createHTML
import org.springframework.stereotype.Service

/**
 * Created by jack on 2017/7/22.
 */
@Service
class HelloDSLView {
    fun html(): String {
        return createHTML().html {
            head {
                meta {
                    charset = "utf-8"
                    httpEquiv = "X-UA-Compatible"
                    content = "IE=edge"
                }
                title("百度一下")
                link {
                    href = "https://cdn.bootcss.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css"
                    rel = "stylesheet"
                }
                script {
                    src = "https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"
                }
                link {
                    href = "dsl.css"
                    rel = "stylesheet"
                }
                script {
                    src = "dsl.js"
                }
            }

            body {
                div(classes = "container") {
                    div(classes = "ipad center") {
                        img {
                            src = "https://www.baidu.com/img/bd_logo1.png"
                            width = "270"
                            height = "129"
                        }
                    }

                    form(classes = "form") {
                        input(InputType.text, classes = "form-control ipad") {
                            id = "wd"
                        }
                        button(classes = "btn btn-primary form-control ipad") {
                            id = "baiduBtn"
                            type = ButtonType.submit
                            text("百度一下")

                        }
                    }

                }
            }
        }
    }
}

対照的に、DSLスタイルはネイティブHTMLよりも簡潔でエレガントです。重要なのは、HTMLがKotlinで記述されていることです。つまり、HTMLコードは単純な静的なフロントエンドコードではなくなります。バックエンドインターフェースを直接使用してデータを返し、HTML要素に値を割り当てることができます。JSPやFreemarkerなどのビューテンプレートエンジンのさまざまな判断、ループ、およびその他の文法機能も(もちろん、完全に超えています)、強力なプログラミング言語Kotlinで記述されたHTMLコードを直接使用します。

次に、コントローラーレイヤーのコードでKotlinビューコードを直接呼び出すことができます。

@Controller
class HelloDSLController {
    @Autowired
    var helloDSLView: HelloDSLView? = null

    @GetMapping("hello")
    fun helloDSL(model: Model): ModelAndView {
        model.addAttribute("hello", helloDSLView?.html())
        return ModelAndView("hello")
    }
}

簡単にするために、ビュー解析エンジンとしてFreemarkerを借用していますが、それはKotlinビューコードをそのまま送信することのみを担当します。hello.ftlコードは次のとおりです。

${hello}

ソースコードのディレクトリは以下の通りです

── src
    ├── main
    │   ├── java
    │   ├── kotlin
    │   │   └── com
    │   │       └── easy
    │   │           └── kotlin
    │   │               └── chapter14_kotlin_dsl
    │   │                   ├── Chapter14KotlinDslApplication.kt
    │   │                   ├── controller
    │   │                   │   └── HelloDSLController.kt
    │   │                   └── view
    │   │                       └── HelloDSLView.kt
    │   └── resources
    │       ├── application.properties
    │       ├── banner.txt
    │       ├── static
    │       │   ├── dsl.css
    │       │   ├── dsl.js
    │       │   └── hello.html
    │       └── templates
    │           └── hello.ftl
    └── test
        ├── java
        ├── kotlin
        │   └── com
        │       └── easy
        │           └── kotlin
        │               └── chapter14_kotlin_dsl
        │                   └── Chapter14KotlinDslApplicationTests.kt
        └── resources

次に、SpringBootアプリケーションを起動して実行し、ブラウザーでhttp://127.0.0.1:8888/helloにアクセスします。次の出力インターフェイスが表示されます。

スクリーンショット2017-07-23 03.53.07.png

これはDSLの繊細さです。kotlinx.htmlを使用して、後でKotlin言語のフロントエンドコードを記述することができます。Web開発を行う場合、通常はHTML +テンプレートエンジン(Velocity、JSP、Freemarkerなど)を使用して、フロントエンドコードとバックエンドコードを統合します。これにより、当惑することがあります。テンプレートエンジンの構文を学習するには、フロントエンドHTMLを処理する必要があります。乱雑なテンプレートエンジンのタグ、変数、およびコード内のコードの他のフラグメント。

Kotlin DSLを使用してHTMLコードを記述する状況は完全に異なります。フロントエンドとバックエンドの統合コーディングの楽しさを取り戻します(フロントエンドHTMLを備えたテンプレートエンジンではなくなり、あらゆる種類の奇妙な#、<#>、$ {}テンプレート言語タグ)、よりエレガントでシンプルなDSLスタイルのHTMLコードをバックエンドに直接移動しました。同時に、HTMLの要素はバックエンドデータとシームレスに直接対話します。これは、Kotlin(もちろん、対応するフィールドのDSLの基本的なセマンティクス)によってのみ行われますモデルはまだ学習する必要があります)。

ヒント:このセクションのプロジェクトのソースコード:https://github.com/EasyKotlin/chapter14_kotlin_dsl

最小限のhttp DSLを実装する

これで基本的に、KotlinのDSLがどのように見えるかがわかりました。しかし、これらのDSLはどのように実装されていますか?このセクションでは、最小限のhttp DSLを実装してDSLを作成する背後にある基本原則を学びます。

ここでは、jqueryのAjax httpリクエストに類似したDSLを実装するために、OkHttpの単純なカプセル化を行います。

OkHttpは成熟した強力なネットワークライブラリであり、Androidソースコードの元のHttpURLConnectionを置き換えるために使用されています。PicassoやRetrofitなどの多くの有名なフレームワークも、基礎となるフレームワークとしてOkHttpを使用しています。

ヒント:OkHttpの使用の詳細については、http://square.github.io/okhttp/を参照してください。

Kotlin Gradleプロジェクトを作成する

最初にIDEAを使用してKotlin Gradleプロジェクトを作成します

スクリーンショット2017-07-23 18.43.04.png

次に、build.gradleで依存関係を構成します

    compile 'com.github.ReactiveX:RxKotlin:2.1.0'
    compile group: 'com.squareup.okhttp3', name: 'okhttp', version: '3.8.1'
    compile group: 'com.alibaba', name: 'fastjson', version: '1.2.35'

その中で、RxKotlinはKotlin言語用のReactiveXフレームワークのサポートライブラリです。ここでは、リクエストコールバックの非同期処理に主にRxKotlinを使用します。

「com.github.ReactiveX:RxKotlin:2.1.0」を使用しています。このライブラリはhttps://jitpack.ioにあるため、jitpackリポジトリをリポジトリ設定に追加します

repositories {
    maven { url 'https://jitpack.io' }
    ...
}

RxKotlin

ReactiveXはReactive Extensionsの略で、通常はRxと略されます。元々はLINQの拡張でした。MicrosoftのアーキテクトErik Meijerが率いるチームによって開発され、2012年11月にオープンソース化されました。

Rxはオブザーバーモードを拡張して、データとイベントのシーケンスをサポートします。Rxは、開発者が非同期I / O(非ブロッキング)データストリームをより便利に処理できるように一貫したプログラミングインターフェイスを提供することを目的とするプログラミングモデルです。

Rxライブラリは.NET、JavaScript、C ++をサポートしています。Rxは近年ますます人気が高まり、現在ではほとんどすべての人気のあるプログラミング言語をサポートしています。言語のリストは次のとおりです:

Rxでサポートされているプログラミング言語 プロジェクトホームページ
ジャワ RxJava:https://github.com/ReactiveX/RxJava
JavaScript RxJS:https://github.com/ReactiveX/rxjs
C# Rx.NETます。https://github.com/Reactive-Extensions/Rx.NET
C#(Unity) UniRx:https://github.com/neuecc/UniRx
Scala RxScala:https://github.com/ReactiveX/RxScala
Clojure RxClojure:https://github.com/ReactiveX/RxClojure
C ++ RxCpp:https://github.com/Reactive-Extensions/RxCpp
取る RxLua:https://github.com/bjornbytes/RxLua
ルビー Rx.rb:https://github.com/Reactive-Extensions/Rx.rb
Python: RxPY:https://github.com/ReactiveX/RxPY
行く RxGo:https://github.com/ReactiveX/RxGo
グルーヴィー RxGroovy:https://github.com/ReactiveX/RxGroovy
JRuby RxJRuby:https://github.com/ReactiveX/RxJRuby
コトリン RxKotlin:https://github.com/ReactiveX/RxKotlin
迅速 RxSwift:https://github.com/kzaher/RxSwift
PHP RxPHP:https://github.com/ReactiveX/RxPHP
エリクサー reaxive:https://github.com/alfert/reaxive
ダーツ RxDart:https://github.com/ReactiveX/rxdart

Rxの言語ライブラリのほとんどは、組織ReactiveXによって管理されています。Rxのより人気のあるライブラリには、RxJava / RxJS / Rx.NETなどが含まれます。もちろん、RxKotlinは今後さらに人気が高くなるでしょう。

ヒント:RxのコミュニティWebサイトはhttp://reactivex.io/です。Githubアドレス:https://github.com/ReactiveX/

HTTPリクエストオブジェクトパッケージクラス

まず、Httpリクエストオブジェクトパッケージクラスを次のように設計します。

class HttpRequestWrapper {

    var url: String? = null

    var method: String? = null

    var body: RequestBody? = null

    var timeout: Long = 10

    internal var success: (String) -> Unit = {}
    internal var fail: (Throwable) -> Unit = {}

    fun success(onSuccess: (String) -> Unit) {
        success = onSuccess
    }

    fun error(onError: (Throwable) -> Unit) {
        fail = onError
    }
}

HttpRequestWrapperのメンバー変数と関数について、次の表で説明します

メンバー 説明
url リクエストURL
方法 Get、Postなどのリクエストメソッドは大文字と小文字を区別しません
リクエストヘッダー、簡単にするために、OkHttpのRequestBodyタイプを直接使用します
タイムアウト タイムアウト時間はmsで、デフォルト値を10秒に設定します
成功 成功したリクエストの関数変数
不合格 リクエストが失敗した関数変数
楽しい成功(onSuccess:(String)-> Unit) リクエスト成功コールバック関数
fun error(onError:(Throwable)-> Unit) 失敗したコールバック関数のリクエスト

http実行エンジン

OkHttpのHttpリクエストAPIを直接呼び出します

private fun call(wrap: HttpRequestWrapper): Response {

    var req: Request? = null
    when (wrap.method?.toLowerCase()) {
        "get" -> req = Request.Builder().url(wrap.url).build()
        "post" -> req = Request.Builder().url(wrap.url).post(wrap.body).build()
        "put" -> req = Request.Builder().url(wrap.url).put(wrap.body).build()
        "delete" -> req = Request.Builder().url(wrap.url).delete(wrap.body).build()
    }

    val http = OkHttpClient.Builder().connectTimeout(wrap.timeout, TimeUnit.MILLISECONDS).build()
    val resp = http.newCall(req).execute()
    return resp
}

リクエストのレスポンスオブジェクトResponseを返します。

OkHttpClient.Builder().connectTimeout(wrap.timeout, TimeUnit.MILLISECONDS).build()タイムアウト期間設定する単位TimeUnit.MILLISECONDSです。

我们通过wrap.method?.toLowerCase()处理请求方法的大小写的兼容。

使用 RxKotlin 完成请求响应的异步处理

我们首先新建一个数据发射源:一个可观察对象(Observable),作为发射数据用

    val sender = Observable.create<Response>({
        e ->
        e.onNext(call(wrap))
    })

其中,e 的类型是 io.reactivex.Emitter (发射器),它的接口定义是

public interface Emitter<T> {
    void onNext(@NonNull T value);
    void onError(@NonNull Throwable error);
    void onComplete();
}

其方法功能简单说明如下:

方法 功能
onNext 发射一个正常值数据(value)
onError 发射一个Throwable异常
onComplete 发射一个完成的信号

这里,我们通过调用onNext方法,把 OkHttp 请求之后的响应对象Response 作为正常值发射出去。

然后我们再创建一个数据接收源:一个观察者(Observer)

    val receiver: Observer<Response> = object : Observer<Response> {
        override fun onNext(resp: Response) {
            wrap.success(resp.body()!!.string())
        }

        override fun onError(e: Throwable) {
            wrap.fail(e)
        }

        override fun onSubscribe(d: Disposable) {
        }

        override fun onComplete() {
        }

    }

receiver 的 onNext 函数接收 sender 发射过来的数据 Response, 然后我们在函数体内,调用这个响应对象,给 wrap.success 回调函数进行相关的赋值操作。同样的,onError 函数中也执行相应的赋值操作。

最后,通过 subscribe 订阅函数来绑定 sender 与 receiver 的关联:

sender.subscribe(receiver)

作为接收数据的 receiver (也就是 观察者 (Observer) ),对发送数据的 sender (也就是可被观察对象( Observable)) 所发射的数据或数据序列作出响应。

这种模式可以极大地简化并发操作,因为它创建了一个处于待命状态的观察者,在未来某个时刻响应 sender 的通知,而不需要阻塞等待 sender 发射数据。这个很像协程中的通道编程模型。

DSL主函数 ajax

我们的ajax DSL主函数设计如下:

fun ajax(init: HttpRequestWrapper.() -> Unit) {
    val wrap = HttpRequestWrapper()
    wrap.init()
    doCall(wrap)
}

其中,参数init: HttpRequestWrapper.() -> Unit 是一个带接收者的函数字面量,它的类型是init = Function1<com.kotlin.easy.HttpRequestWrapper, kotlin.Unit>。 HttpRequestWrapper是扩展函数init()的接收者,点号 . 是扩展函数修饰符。

我们在函数体内直接调用了这个函数字面量 wrap.init() 。这样的写法可能比较难以理解,这个函数字面量 init 的调用实际上是 init.invoke(wrap) ,就是把传入 ajax 的函数参数直接传递给 wrap 。为了更简单的理解这个 init 函数的工作原理,我们通过把上面的 ajax 函数的代码反编译成对应的 Java 代码如下:

   public static final void ajax(@NotNull Function1 init) {
      Intrinsics.checkParameterIsNotNull(init, "init");
      HttpRequestWrapper wrap = new HttpRequestWrapper();
      init.invoke(wrap);
      doCall(wrap);
   }

也就是说,ajax 函数的一个更容易理解的写法是

fun ajax(init: HttpRequestWrapper.() -> Unit) {
    val wrap = HttpRequestWrapper()
    init.invoke(wrap)
    doCall(wrap)
}

我们在实际应用的时候,可以直接把 init 写成Lambda 表达式的形式,因为接收者类型HttpRequestWrapper 可以从上下文推断出来。

我们这样调用 ajax 函数:

ajax {
    url = testUrl
    method = "get"
    success {
        string ->
        println(string)
        Assert.assertTrue(string.contains("百度一下"))
    }
    error {
        e ->
        println(e.message)
    }
}

下面是几个测试代码示例:

package com.kotlin.easy

import com.alibaba.fastjson.JSONObject
import okhttp3.MediaType
import okhttp3.RequestBody
import org.junit.Assert
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4

/**
 * Created by jack on 2017/7/23.
 */

@RunWith(JUnit4::class)
class KAjaxTest {

    @Test fun testHttpOnSuccess() {
        val testUrl = "https://www.baidu.com"
        ajax {
            url = testUrl
            method = "get"
            success {
                string ->
                println(string)
                Assert.assertTrue(string.contains("百度一下"))
            }
            error {
                e ->
                println(e.message)
            }
        }

    }

    @Test fun testHttpOnError() {
        val testUrl = "https://www2.baidu.com"

        ajax {
            url = testUrl
            method = "get"
            success {
                string ->
                println(string)
            }
            error {
                e ->
                println(e.message)
                Assert.assertTrue("connect timed out" == e.message)
            }
        }
    }


    @Test fun testHttpPost() {
        var json = JSONObject()
        json.put("name", "Kotlin DSL Http")
        json.put("owner", "Kotlin")
        val postBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), json.toString())
        ajax {
            url = "saveArticle"
            method = "post"
            body = postBody
            success {
                string ->
                println(string)
            }
            error {
                e ->
                println(e.message)
            }
        }
    }


    @Test fun testLambda() {
        val testUrl = "https://www.baidu.com"

        val init: HttpRequestWrapper.() -> Unit = {
            this.url = testUrl
            this.method = "get"
            this.success {
                string ->
                println(string)
                Assert.assertTrue(string.contains("百度一下"))
            }
            this.error {
                e ->
                println(e.message)
            }
        }
        ajax(init)
    }

到这里,我们已经完成了一个极简的 Kotlin Ajax DSL。

本节工程源码: https://github.com/EasyKotlin/chatper14_kotlin_dsl_http

本章小结

相比于Java,Kotlin对函数式编程的支持更加友好。Kotlin 的扩展函数和高阶函数(Lambda 表达式),为定义Kotlin DSL提供了核心的特性支持。

使用DSL的代码风格,可以让我们的程序更加直观易懂、简洁优雅。如果使用Kotlin来开发项目的话,我们完全可以去尝试一下。


Kotlin开发者社区

专注分享 Java、 Kotlin、Spring/Spring Boot、MySQL、redis、neo4j、NoSQL、Android、JavaScript、React、Node、函数式编程、编程思想、"高可用,高性能,高实时"大型分布式系统架构设计主题。

High availability, high performance, high real-time large-scale distributed system architecture design

分布式框架:Zookeeper、分布式中间件框架等
分布式存储:GridFS、FastDFS、TFS、MemCache、redis等
分布式数据库:Cobar、tddl、Amoeba、Mycat
云计算、大数据、AI算法
虚拟化、云原生技术
分布式计算框架:MapReduce、Hadoop、Storm、Flink等
分布式通信机制:Dubbo、RPC调用、共享远程数据、消息队列等
消息队列MQ:Kafka、MetaQ,RocketMQ
怎样打造高可用系统:基于硬件、软件中间件、系统架构等一些典型方案的实现:HAProxy、基于Corosync+Pacemaker的高可用集群套件中间件系统
Mycat架构分布式演进
大数据Join背后的难题:数据、网络、内存和计算能力的矛盾和调和
Java分布式系统中的高性能难题:AIO,NIO,Netty还是自己开发框架?
高性能事件派发机制:线程池模型、Disruptor模型等等。。。

合抱之木,生于毫末;九层之台,起于垒土;千里之行,始于足下。不积跬步,无以至千里;不积小流,无以成江河。

Kotlin 简介

Kotlin是一门非研究性的语言,它是一门非常务实的工业级编程语言,它的使命就是帮助程序员们解决实际工程实践中的问题。使用Kotlin 让 Java程序员们的生活变得更好,Java中的那些空指针错误,浪费时间的冗长的样板代码,啰嗦的语法限制等等,在Kotlin中统统消失。Kotlin 简单务实,语法简洁而强大,安全且表达力强,极富生产力。

Java诞生于1995年,至今已有23年历史。当前最新版本是 Java 9。在 JVM 生态不断发展繁荣的过程中,也诞生了Scala、Groovy、Clojure 等兄弟语言。

Kotlin 也正是 JVM 家族中的优秀一员。Kotlin是一种现代语言(版本1.0于2016年2月发布)。它最初的目的是像Scala那样,优化Java语言的缺陷,提供更加简单实用的编程语言特性,并且解决了性能上的问题,比如编译时间。 JetBrains在这些方面做得非常出色。

Kotlin语言的特性

用 Java 开发多年以后,能够尝试一些新的东西真是太棒了。如果您是 Java 开发人员,使用 Kotlin 将会非常自然流畅。如果你是一个Swift开发者,你将会感到似曾相识,比如可空性(Nullability)。 Kotlin语言的特性有:

1.简洁

大幅减少样板代码量。

2.与Java的100%互操作性

Kotlin可以直接与Java类交互,反之亦然。这个特性使得我们可以直接重用我们的代码库,并将其迁移到 Kotlin中。由于Java的互操作性几乎无处不在。我们可以直接访问平台API以及现有的代码库,同时仍然享受和使用 Kotlin 的所有强大的现代语言功能。

3.扩展函数

Kotlin 类似于 C# 和 Gosu, 它提供了为现有类提供新功能扩展的能力,而不必从该类继承或使用任何类型的设计模式 (如装饰器模式)。

4.函数式编程

Kotlin 语言一等支持函数式编程,就像Scala一样。具备高阶函数、Lambda 表达式等函数式基本特性。

5.默认和命名参数

在Kotlin中,您可以为函数中的参数设置一个默认值,并给每个参数一个名称。这有助于编写易读的代码。

6.强大的开发工具支持

そして、それはJetBrainsによって作成されているため、優れたIDEサポートがあります。JavaからKotlinへの自動変換は100%OKではありませんが、実際には非常に優れたツールです。IDEAのツールを使用してJavaコードをKotlinコードに変換する場合、結果のコードの60%〜70%は簡単に再利用でき、変更のコストはわずかです。

簡潔で強力な構文機能に加えて、Kotlinには非常に実用的なAPIとその周りに構築されたエコシステムもあります。例:コレクションAPI、IO拡張、リフレクションAPIなど。同時に、Kotlinコミュニティは、豊富なドキュメント、多くの学習資料、オンラインREPLも提供しています。

開発者を幸せにする最新のプログラミング言語。永遠にオープンソース

「Kotlinのエントリから高度な戦闘まで」の画像(陳光建、清華大学出版局)

「Kotlinのエントリから高度な戦闘まで」の画像(陳光建、清華大学出版局)

https://kotlinlang.org/

おすすめ

転載: blog.csdn.net/universsky2015/article/details/108669474