首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

用Kotlin构建神奇的DSL

本期文章来自猎萝卜内部技术分享

DSL(Domain Specified Language)领域专用语言

常见的DSL

正则表达式

通过一些规定好的符号和组合规则,通过正则表达式引擎来实现字符串的匹配

HTML&CSS

虽然写的是类似XML 或者 .{} 一样的字符规则,但是最终都会被浏览器内核转变成Dom树,从而渲染到Webview上

SQL

虽然是一些诸如 create select insert 这种单词后面跟上参数,这样的语句实现了对数据库的增删改查一系列程序工作

DSL分类

内部 DSL(从一种宿主语言构建而来)

外部 DSL(从零开始构建的语言,需要实现语法分析器等)

通过Kotlin构建类型安全的DSL

例子:

这是在kotlin中完全合法的一段代码,并且可以正确运行出结果,得到的结果如下图

这就是我们自定义DSL构造器得出的结果。

首先我们回顾一些kotlin技术:

lambda与高阶函数

Kotlin 的 lambda 有个规约:如果 lambda 表达式是函数的最后一个实参,则可以放在括号外面,并且可以省略括号,这个规约是 Kotlin DSL 实现嵌套结构的本质原因。

传递lambda表达式作为参数:`,这个方法接收一个有receiver的lambda表达式,因为这样在block的内部就可以直接访问receiver的公共成员了,这一点也很重要。

扩展函数(扩展属性)

对于同样作为静态语言的 Kotlin 来说,扩展函数(扩展属性)是让他拥有类似于动态语言能力的法宝,即我们可以为任意对象动态的增加函数或属性。

比如,为 LocalDate 扩展一个函数::

与 JavaScript 这类动态语言不一样,Kotlin 实现原理是: 提供静态工具类,将接收对象(此例为 String )做为参数传递进来,以下为该扩展函数编译成 Java 的代码

在Kotlin语言中,类不再是语言的最小单位。我们既可以单独声明一个全局函数,也可以声明全局变量。因此,你可以认为toLong是一个函数整体,这个函数的接收者可以是任意对象。

而对于Java,Java语言中所有的行为都必须在类体中完成。具体到某个函数或某一个变量始终属于某一个类实例。换而言之,其Receiver是固定的,也就没有了所谓Receiver的概念。

一元运算符

开始分析

实现原理

首先看

这个代码块的实质是一个函数调用

这个函数接受一个名为的参数,该参数本身就是一个函数。 该函数的类型是,它是一个带接收者的函数类型。 这意味着我们需要向函数传递一个 HTML 类型的实例(接收者), 并且我们可以在函数内部调用该实例的成员。 该接收者可以通过this关键字访问:

(和是的成员函数。)

现在,像往常一样,this可以省略掉了,我们得到的东西看起来已经非常像一个构建器了:

它创建了一个的新实例,然后通过调用作为参数传入的函数来初始化它 (在我们的示例中,归结为在HTML实例上调用和),然后返回此实例。 这正是构建器所应做的。

类中的和函数的定义与类似。 唯一的区别是,它们将构建的实例添加到包含实例的集合中:

实际上这两个函数做同样的事情,所以我们可以有一个泛型版本,:

所以,现在我们的函数很简单:

并且我们可以使用它们来构建和标签。

这里要讨论的另一件事是如何向标签体中添加文本。在上例中我们这样写到:

所以基本上,我们只是把一个字符串放进一个标签体内部,但在它前面有一个小的, 所以它是一个函数调用,调用一个前缀操作。 该操作实际上是由一个扩展函数定义的,该函数是抽象类(的父类)的成员:

所以,在这里前缀所做的事情是把一个字符串包装到一个实例中,并将其添加到集合中, 以使其成为标签树的一个适当的部分。

作用域控制

由于内部的作用域默认可以获得外部的隐式接收器

我们可以使用来注释一个注解

注释类被称为一个DSL标记,它被注解注释。

一般规则:

如果隐式接收器用@HtmlTagMarker相应的DSL标记注释标记,则它可以属于DSL

同一DSL的两个隐式接收器在同一范围内不可访问

就近原则

其他可用的接收器可以照常解析,但如果得到的解析调用绑定到这样的接收器,则编译错误

标记规则:隐式接收器被视为被注释,需要满足下面的条件:

它的类型是被标记,或

它的类型分类器被标记

或其任何超类/超接口

补充说明

无论是否被标记,都可以访问接收器

完整代码

应用

kotlin官方html构造器:kotlinx.html

kotlin的javaFX框架:TornadoFX

安卓布局框架:anko

kotlin服务端框架:ktor

参考文档

类型安全的构建器

Scope control for implicit receivers

Kotlin之美——DSL篇

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20181027B18T7M00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券