欧美一级特黄大片做受成人-亚洲成人一区二区电影-激情熟女一区二区三区-日韩专区欧美专区国产专区

kotlin更多語言結(jié)構(gòu)——>類型安全的構(gòu)建器-創(chuàng)新互聯(lián)

通過使用命名得當(dāng)?shù)暮瘮?shù)作為構(gòu)建器,結(jié)合帶有接收者的函數(shù)字面值,可以在 Kotlin 中創(chuàng)建類型安全、靜態(tài)類型 的構(gòu)建器kotlin更多語言結(jié)構(gòu)——&g
t;類型安全的構(gòu)建器

類型安全的構(gòu)建器可以創(chuàng)建基于 Kotlin 的適用于采用半聲明方式構(gòu)建復(fù)雜層次數(shù)據(jù)結(jié)構(gòu)領(lǐng)域?qū)S谜Z言(DSL)。 以下是構(gòu)建器的一些示例應(yīng)用場景:

茌平ssl適用于網(wǎng)站、小程序/APP、API接口等需要進(jìn)行數(shù)據(jù)傳輸應(yīng)用場景,ssl證書未來市場廣闊!成為成都創(chuàng)新互聯(lián)的ssl證書銷售渠道,可以享受市場價格4-6折優(yōu)惠!如果有意向歡迎電話聯(lián)系或者加微信:13518219792(備注:SSL證書合作)期待與您的合作!

— 使用 Kotlin 代碼生成標(biāo)記語言,例如 HTML 或 XML;

— 以編程方式布局UI組件:Anko;
    — 為Web服務(wù)器配置路由:Ktor。

一個類型安全的構(gòu)建器示例

考慮下面的代碼

import com.example.html.* // 參?下文聲明 fun result() = html { head { title { +"XML encoding with Kotlin" } } body { h1 { +"XML encoding with Kotlin" } p { +"this format can be used as an alternative markup to XML" } // 一個具有屬性和文本內(nèi)容的元素 a() { +"Kotlin" } // 混合的內(nèi)容 p { +"This is some" b { +"mixed" } +"text. For more see the" a() { +"Kotlin" } +"project" } p { +"some text" } // 以下代碼生成的內(nèi)容 p { for (arg in args) +arg } } }

這是完全合法的 Kotlin 代碼。你可以在這里在線運行上文代碼(修改它并在瀏覽器中運行)

實現(xiàn)原理

讓我們來看看 Kotlin 中實現(xiàn)類型安全構(gòu)建器的機(jī)制。首先,我們需要定義我們想要構(gòu)建的模型,在本例中我們 需要建模 HTML 標(biāo)簽。用一些類就可以輕易完成。例如,HTML 是一個描述 <html> 標(biāo)簽的類,也就是說它定 義了像 <head> 和 <body> 這樣的子標(biāo)簽。(參?下文它的聲明。)

現(xiàn)在,讓我們回想下為什么我們可以在代碼中這樣寫

html { // ...... }

html 實際上是一個函數(shù)調(diào)用,它接受一個 lambda 表達(dá)式 作為參數(shù)。該函數(shù)定義如下

fun html(init: HTML.() -> Unit): HTML { val html = HTML() html.init() return html }

這個函數(shù)接受一個名為 init 的參數(shù),該參數(shù)本身就是一個函數(shù)。該函數(shù)的類型是 HTML.() -> Unit,它是 一個 帶接收者的函數(shù)類型 。這意味著我們需要向函數(shù)傳遞一個 HTML 類型的實例( 接收者 ),并且我們可以在 函數(shù)內(nèi)部調(diào)用該實例的成員。該接收者可以通過 this 關(guān)鍵字訪問

html { this.head { ...... } this.body { ...... } }

(head 和 body 是 HTML 的成員函數(shù)。)

現(xiàn)在,像往常一樣,this 可以省略掉了,我們得到的東西看起來已經(jīng)非常像一個構(gòu)建器了

html { head { ...... } body { ...... } }

那么,這個調(diào)用做什么?讓我們看看上面定義的 html 函數(shù)的主體。它創(chuàng)建了一個 HTML 的新實例,然后通過 調(diào)用作為參數(shù)傳入的函數(shù)來初始化它(在我們的示例中,歸結(jié)為在HTML實例上調(diào)用 head 和 body),然后返 回此實例。這正是構(gòu)建器所應(yīng)做的。

HTML 類中的 head 和 body 函數(shù)的定義與 html 類似。唯一的區(qū)別是,它們將構(gòu)建的實例添加到包含 HTML 實例的 children 集合中

fun head(init: Head.() -> Unit) : Head { val head = Head() head.init() children.add(head) return head } fun body(init: Body.() -> Unit) : Body { val body = Body() body.init() children.add(body) return body }

實際上這兩個函數(shù)做同樣的事情,所以我們可以有一個泛型版本,initTag

protected fun <T : Element> initTag(tag: T, init: T.() -> Unit): T { tag.init() children.add(tag) return tag }

所以,現(xiàn)在我們的函數(shù)很簡單

fun head(init: Head.() -> Unit) = initTag(Head(), init) fun body(init: Body.() -> Unit) = initTag(Body(), init)

并且我們可以使用它們來構(gòu)建 <head> 和 <body> 標(biāo)簽。

這里要討論的另一件事是如何向標(biāo)簽體中添加文本。在上例中我們這樣寫到

html { head { title {+"XML encoding with Kotlin"} } // ...... }

所以基本上,我們只是把一個字符串放進(jìn)一個標(biāo)簽體內(nèi)部,但在它前面有一個小的 +,所以它是一個函數(shù)調(diào)用, 調(diào)用一個前綴 unaryPlus() 操作。該操作實際上是由一個擴(kuò)展函數(shù) unaryPlus() 定義的,該函數(shù)是TagWithText 抽象類(Title 的父類)的成員

operator fun String.unaryPlus() { children.add(TextElement(this)) }

所以,在這里前綴 + 所做的事情是把一個字符串包裝到一個 TextElement 實例中,并將其添加到 children 集合中,以使其成為標(biāo)簽樹的一個適當(dāng)?shù)牟糠帧?/p>

所有這些都在上面構(gòu)建器示例頂部導(dǎo)入的包 com.example.html 中定義。在最后一節(jié)中,你可以閱讀這個包 的完整定義

作用域控制:@DslMarke(r 自 1.1 起)

  使用 DSL 時,可能會遇到上下文中可以調(diào)用太多函數(shù)的問題。我們可以調(diào)用 lambda 表達(dá)式內(nèi)部每個可用的隱式接收者的方法,因此得到一個不一致的結(jié)果,就像在另一個 head 內(nèi)部的 head 標(biāo)記那樣 html { head { head {} // 應(yīng)該禁止 } // ...... }

在這個例子中,必須只有最近層的隱式接收者 this@head 的成員可用;head() 是外部接收者 this@html 的成員,所以調(diào)用它一定是非法的。

為了解決這個問題,在 Kotlin 1.1 中引入了一種控制接收者作用域的特殊機(jī)制。

為了使編譯器開始控制標(biāo)記,我們只是必須用相同的標(biāo)記注解來標(biāo)注在 DSL 中使用的所有接收者的類型。例如,對于 HTML 構(gòu)建器,我們聲明一個注解 @HTMLTagMarker

@DslMarker annotation class HtmlTagMarker

如果一個注解類使用 @DslMarker 注解標(biāo)注,那么該注解類稱為 DSL 標(biāo)記。

在我們的 DSL 中,所有標(biāo)簽類都擴(kuò)展了相同的超類 Tag 。只需使用 @HtmlTagMarker 來標(biāo)注超類就足夠了,之后,Kotlin 編譯器會將所有繼承的類視為已標(biāo)注

@HtmlTagMarker abstract class Tag(val name: String) { ...... }

我們不必用 @HtmlTagMarker 標(biāo)注 HTML 或 Head 類,因為它們的超類已標(biāo)注過

class HTML() : Tag("html") { ...... } class Head() : Tag("head") { ...... }

在添加了這個注解之后,Kotlin 編譯器就知道哪些隱式接收者是同一個 DSL 的一部分,并且只允許調(diào)用最近層 的接收者的成員

html { head { head { } // 錯誤:外部接收者的成員 } // ...... }

請注意,仍然可以調(diào)用外部接收者的成員,但是要做到這一點,你必須明確指定這個接收者

html { head { this@html.head { } // 可能 } // ...... }

com.example.html 包的完整定義

這就是 com.example.html 包的定義(只有上面例子中使用的元素)。它構(gòu)建一個 HTML 樹。代碼中大量使 用了擴(kuò)展函數(shù)和帶有接收者的 lambda 表達(dá)式。

請注意,@DslMarker 注解在 Kotlin 1.1 起才可用

package com.example.html interface Element { fun render(builder: StringBuilder, indent: String) } class TextElement(val text: String) : Element { override fun render(builder: StringBuilder, indent: String) { builder.append("$indent$text ") } } @DslMarker annotation class HtmlTagMarker @HtmlTagMarker abstract class Tag(val name: String) : Element { val children = arrayListOf<Element>() val attributes = hashMapOf<String, String>() protected fun <T : Element> initTag(tag: T, init: T.() -> Unit): T { tag.init() children.add(tag) return tag } override fun render(builder: StringBuilder, indent: String) { builder.append("$indent<$name${renderAttributes()}> ") for (c in children) { c.render(builder, indent + " ") } builder.append("$indent</$name> ") } private fun renderAttributes(): String { val builder = StringBuilder() for ((attr, value) in attributes) { builder.append(" $attr="$value"") } return builder.toString() } override fun toString(): String { val builder = StringBuilder() render (builder, "") return builder.toString() } } abstract class TagWithText(name: String) : Tag(name) { operator fun String.unaryPlus() { children.add(TextElement(this)) } } class HTML : TagWithText("html") { fun head(init: Head.() -> Unit) = initTag(Head(), init) fun body(init: Body.() -> Unit) = initTag(Body(), init) } class Head : TagWithText("head") { fun title(init: Title.() -> Unit) = initTag(Title(), init) } class Title : TagWithText("title") abstract class BodyTag(name: String) : TagWithText(name) { fun b(init: B.() -> Unit) = initTag(B(), init) fun p(init: P.() -> Unit) = initTag(P(), init) fun h1(init: H1.() -> Unit) = initTag(H1(), init) fun a(href: String, init: A.() -> Unit) { val a = initTag(A(), init) a.href = href } } class Body : BodyTag("body") class B : BodyTag("b") class P : BodyTag("p") class H1 : BodyTag("h1") class A : BodyTag("a") { var href: String get() = attributes["href"]!! set(value) { attributes["href"] = value } } fun html(init: HTML.() -> Unit): HTML { val html = HTML() html.init() return html }

分享標(biāo)題:kotlin更多語言結(jié)構(gòu)——&gt;類型安全的構(gòu)建器-創(chuàng)新互聯(lián)
轉(zhuǎn)載來源:http://aaarwkj.com/article6/dohcig.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站收錄、品牌網(wǎng)站建設(shè)、網(wǎng)站改版、外貿(mào)建站關(guān)鍵詞優(yōu)化、網(wǎng)站內(nèi)鏈

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

成都做網(wǎng)站
中文字幕国产精品欧美| 欧美日韩在线一区二区| 日韩精品中文字幕欧美乱| 亚洲国产午夜福利在线69| av天堂资源地址在线观看| 高清白嫩学生自拍视频| 老女人性生交大片免费| 亚洲天堂日韩欧美在线| 国产精品自拍午夜福利| 亚洲国产丁香综合激情啪| 日韩av网址在线免费观看| 亚洲三级成人一区在线| 欧美日本一道本一区二区三区 | 国产一区二区av免费| 亚洲黄色av乱码在线观看| 91精品欧美综合在线| 亚洲国产女人精品久久久| 国产精品日韩精品在线| av 一区二区三区av| 午在线亚洲男人午在线| 91麻豆亚洲国产成人久久| 黑寡妇精品欧美一区二区毛| 国产极品嫩模在线观看91| 免费的黄色片带中文字幕| 精品少妇人妻av免费久久久| 人妻中文字幕在线av| 日韩亚洲在线中文字幕| 成人性生交免大片免费| 亚洲综合色一区二区三区四区 | 欧美亚洲中文字幕高清| 一区二区三区高清人妻| 亚洲日本欧美激情综合| 欧美日韩一区二区三区大片| 国产av无毛一区二区三区| 亚洲综合中文字幕精品| 亚洲一区二区三区 日韩精品| 日本九州不卡久久精品一区| 亚洲精品色婷婷一区二区| 日韩一区二区偷拍视频| 岛国av在线免费观看| 日本黄色大波少妇网站|