主程序代码
fun main(args: Array<String>) {
val result =
html {
head {
title { +"HTML encoding with Kotlin" }
}
body {
h1 { +"HTML encoding with Kotlin" }
p { +"this format can be used as an alternative markup to HTML" }
// an element with attributes and text content
a(href = "http://jetbrains.com/kotlin") { +"Kotlin" }
// mixed content
p {
+"This is some"
b { +"mixed" }
+"text. For more see the"
a(href = "http://jetbrains.com/kotlin") { +"Kotlin" }
+"project"
}
p { +"some text" }
// content generated from command-line arguments
p {
+"Command line arguments were:"
ul {
for (arg in args)
li { +arg }
}
}
}
}
println(result)
}
问答解析
-
以上代码块中的html是什么?
答:html是一个函数的名字fun html(init: HTML.() -> Unit): HTML { val Html = HTML() Html.init() return Html }
-
html函数的形参是什么意思?
答:init是形参的名字,HTML.() -> Unit 表示这个函数由HTML类调用,没有参数,并且返回值为Unit,Unit相当于Java里面的void -
html函数里面的Html.init()是什么意思?
答:Html.init()相当于对HTML类的扩展,增加了一个init函数。 -
为什么html在调用的时候没有圆括号?
答:html这个函数只有一个参数,而且这个参数是lambda函数这个函数,所以在调用的时候传入的lambda函数体可以放到函数名字后面,并且省略圆括号 -
上面代码块中,html里面的head和body是什么?
答:都是函数,这些函数是HTML类里面的函数。因为html函数的形参中规定这个lambda函数是HTML的拓展函数,所以就可以调用HTML对象中的函数。 -
以上代码块中的+是什么意思?
答: 这个加号已经被重载了,重载函数如下interface Element { ... } abstract class Tag(val name: String) : Element { ... } class TextElement(val text: String) : Element { ... } abstract class TagWithText(name: String) : Tag(name) { //重载运算符`+` operator fun String.unaryPlus() { children.add(TextElement(this)) } }
相关网站:
- https://try.kotlinlang.org/#/Examples/Longer examples/HTML Builder/HTML Builder.kt
- https://kotlinlang.org/docs/reference/lambdas.html#function-literals-with-receiver
- https://blog.youkuaiyun.com/qq_32115439/article/details/74898099
原始代码:
/**
* This is an example of a Type-Safe Groovy-style Builder
*
* Builders are good for declaratively describing data in your code.
* In this example we show how to describe an HTML page in Kotlin.
*
* See this page for details:
* http://kotlinlang.org/docs/reference/type-safe-builders.html
*/
package html
fun main(args: Array<String>) {
val result =
html {
head {
title { +"HTML encoding with Kotlin" }
}
body {
h1 { +"HTML encoding with Kotlin" }
p { +"this format can be used as an alternative markup to HTML" }
// an element with attributes and text content
a(href = "http://jetbrains.com/kotlin") { +"Kotlin" }
// mixed content
p {
+"This is some"
b { +"mixed" }
+"text. For more see the"
a(href = "http://jetbrains.com/kotlin") { +"Kotlin" }
+"project"
}
p { +"some text" }
// content generated from command-line arguments
p {
+"Command line arguments were:"
ul {
for (arg in args)
li { +arg }
}
}
}
}
println(result)
}
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\n")
}
}
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()}>\n")
for (c in children) {
c.render(builder, indent + " ")
}
builder.append("$indent</$name>\n")
}
private fun renderAttributes(): String? {
val builder = StringBuilder()
for (a in attributes.keys) {
builder.append(" $a=\"${attributes[a]}\"")
}
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 ul(init: UL.() -> Unit) = initTag(UL(), init)
fun a(href: String, init: A.() -> Unit) {
val a = initTag(A(), init)
a.href = href
}
}
class Body() : BodyTag("body")
class UL() : BodyTag("ul") {
fun li(init: LI.() -> Unit) = initTag(LI(), init)
}
class B() : BodyTag("b")
class LI() : BodyTag("li")
class P() : BodyTag("p")
class H1() : BodyTag("h1")
class A() : BodyTag("a") {
public var href: String
get() = attributes["href"]!!
set(value) {
attributes["href"] = value
}
}
fun html(init: HTML.() -> Unit): HTML {
val Html = HTML()
Html.init()
return Html
}