引子

我们用一段gradle的脚本做引子,理解这一段脚本与一般的groovy代码是怎么联系起来的

buildscript {
repositories {
jcenter()
mavenLocal()
//或者使用指定的本地maven 库
maven{
url "file://D:/repo"
}
} dependencies {
classpath 'com.android.tools.build:gradle:1.2.3'
}
}

  

DSL的定义

DSL(Domain Specific Language)定义:针对某一领域,具有受限表达性的一种计算机程序设计语言

所谓针对某一领域,其基本思想是“求专不求全”,不像通用目的语言那样目标范围涵盖一切软件问题,而是专门针对某一特定问题的计算机语言。

DSL伴随语义模型出现,语义模型会表现为程序库或者框架,对于构建DSL而言,语义模型不可或缺。DSL只是位于其上的一层而已。定义做什么,而不是用一堆命令语句来描述怎么做,所以它是声明式编程(如SQL),这一点很重要。DSL的受限表达性可以使DSL语言不易出错,即便出错,也易于发现。这是受限表达性的意义。

DSL是通用语言的特定用法。内部DSL通常是一段合法的程序,但是具有特定的风格。而且只用到了语言一部分特性。防止DSL逐渐演变为一种通用语言,要受限表达。目的防止DSL过于复杂,可维护性降低,学习成本提升,偏离方向。不要让DSL读起来向自然语言。它是程序语言,比自然语言更加准确和简洁。语义模型位于语言和DSL之间,为二者解耦。DSL脚本,解析器,语义模型,模型——DSL自上而下几个层次。

Groovy语法对DSL的支持

我们先看一个简单的类和一个奇葩的语法现象:分号省略;默认public省略;有形参的方法调用,括号可以省略;返回的return可以省略,默认最后一行代码的值返回。

import groovy.xml.*
import java.io.* class Task{
//默认省略public和分号
String summary
String description
Date dueDate
Map m static void main(args){
//默认有set和get方法
Task task1 = new Task()
task1.setSummary("this is Task1")
println task1.getSummary()
//有形参的方法调用,括号可以省略
task1.setDescription "this is Task class"
task1.printDescription ""
//可以直接传map
Task task3 = new Task()
task3.setM (['summary':'this is Task3','description':'Task'])
println task3.getM()
//map的分号可以省略
Task task2= new Task('summary':'this is Task2','description':'Task')
println task2.getSummary()
//括号也可以省略
Task task4 = new Task()
task4.setM 'summary':'this is Task4'
println task4.getM()
} public void printDescription(def str){
println "the task description is : $description"
}
}

  

看完省略括号的语法现象,下面看另一个重量级的语法现象——闭包

闭包是用{符号括起来的代码块,它可以被单独运行或调用,也可以被命名。类似‘匿名类’或内联函数的概念。

闭包中最常见的应用是对集合进行迭代,下面定义了3个闭包对map进行了迭代:

map.each({key,value->    //key,value两个参数用于接受每个元素的键/值

println "$key:$value"})

map.each{println it}     //it是一个关键字,代表map集合的每个元素

map.each({ println it.getKey()+"-->"+it.getValue()})

除了用于迭代之外,闭包也可以单独定义:

def say={word->

println "Hi,$word!"

}

调用:

say('groovy')

say.call('groovy&grails')

输出:

Hi,groovy!

Hi,groovy&grails!

看起来,闭包类似于方法,需要定义参数和要执行的语句,它也可以通过名称被调用。然而闭包对象(不要奇怪,闭包也是对象)可以作为参数传递(比如前面的闭包作为参数传递给了map的each方法)。而在java中,要做到这一点并不容易(也许C++中的函数指针可以,但不要忘记java中没有指针)。其次,闭包也可以不命名(当然作为代价,只能在定义闭包时执行一次),而方法不可以。

当闭包遇到括号省略,一切都不一样了

Project.groovy

public class Project{
Date date void setDateFormat(Closure formatDate){
println formatDate(date)
}
}

Main.groovy

public class Main{

    public static void main(def args){
Project p = new Project()
p.setDate new Date()
//正常
p.setDateFormat({
return it.format('yyyy-MM-dd HH:mm:ss')
}) //减return
p.setDateFormat {
it.format('yyyy-MM-dd HH:mm:ss')
} //减括号(是不是很像我们的gradle脚本?) p.setDateFormat {
it.format 'yyyy-MM-dd HH:mm:ss'
} } }

  

减完之后,像不像下面的脚本?

 dependencies {
classpath 'com.android.tools.build:gradle:1.2.3'
}

  

唯一的区别是我们需要用对象来引用方法,其实去掉对象也不难,自己调用自己的方法就可以了,看下面的代码:

public class Project{
Date date void setDateFormat(Closure formatDate){
println formatDate(date)
} //将format内置
String format(String f){
date.format(f)
}
//无形参的方法
void showDate(){
print date.toString()
} void run(){
//对象去掉,是不是一模一样了?
setDateFormat{
println 'this is a scrip'
format 'yyyy-MM-dd HH:mm:ss'
//没有形参的话就只能乖乖写括号了
showDate()
}
}
}

 

DSL的两个关键点,某一领域,gradle只为编译,也只用于编译。受限表达,一般只调用脚本运行上下文环境中的方法,为的就是尽量简单,出错的话,排错方便。伴随而生的语义模型就是那一套编译框架。

Groovy对DSL的支持,表现为可以省略:分号,调用方法的括号,return,默认public等。

参考:

http://docs.groovy-lang.org/latest/html/documentation/

第一篇:groovy对DSL的语法支持的更多相关文章

  1. Bootstrap:Bootstrap_table第一篇:快速用bootstrap_table(支持参数)筛选并展示数据,固定表格前几列,实现表格单元格编辑

    1.准备好css和js文件 <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstr ...

  2. Python编程笔记(第一篇)Python基础语法

    一.python介绍 1.编程语言排行榜 TIOBE榜 TIOBE编程语言排行榜是编程语言流行趋势的一个指标,每月更新,这份排行榜排名基于互联网有经验的程序员.课程和第三方厂商的数量. 2.pytho ...

  3. 【ABAP系列】SAP ABAP7.40新语法简介第一篇

    公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[ABAP系列]SAP ABAP7.40新语法简 ...

  4. 用仿ActionScript的语法来编写html5——第一篇,显示一张图片

    第一篇,显示一张图片 一,代码对比 as代码: public var loader:Loader; public function loadimg():void{ loader = new Loade ...

  5. Groovy 与 DSL

    一:DSL 概念 指的是用于一个特定领域的语言(功能领域.业务领域).在这个给出的概念中有 3个重点: 只用于一个特定领域,而非所有通用领域,比如 Java / C++就是用于通用领域,而不可被称为 ...

  6. 我的第一篇Markdown语法博客

    这是我的第一篇使用markdown语法编写的博客 使用的编辑器为Sublime Text2 并且使用了sublog插件, sublog是一个开源项目 sublog 并且参考了作者的博客 AmongOt ...

  7. 我的第一篇Markdown博客

    我的第一篇Markdown博客 这是我第一次用Markdown写博客,发现还是比较好用的,加上Marsedit也支持了Markdown的博客预览,博客园也加了Markdown的格式支持,就更加方便了, ...

  8. 微型 ORM 的第一篇 DapperLambda发布

    引言:因为接触过多个ORM,但使用的时候都遇到了各自的一些不够理想的地方,从最早开始开始公司自己分装的,到后面用EF,以及Dapper和DapperExtensions  到现在用的FluentDat ...

  9. Scala语言笔记 - 第一篇

    目录 Scala语言笔记 - 第一篇 1 基本类型和循环的使用 2 String相关 3 模式匹配相关 4 class相关 5 函数调用相关 Scala语言笔记 - 第一篇 ​ 最近研究了下scala ...

随机推荐

  1. Java学习笔记(一):数据类型与变量

    数据类型 Java中存在2种数据类型,下面我们来详解一下: 基本数据类型: 引用数据类型: 可以用一张表来记录: 基本数据类型 整型 byte:1个字节8位,取值范围为:[-128, 127],直接写 ...

  2. rqnoj-390-地震了!-动态规划

    一步步的往前走,判断当前状态与上一个状态的关闭. 注意,题目输入的楼层的速度是从小到大,而实际运用的楼层顺序是从大到小.. #include<stdio.h> #include<al ...

  3. Nginx NLB 及Redis学习

    负载均衡: ARR: 微软的应用级别的负载均衡方案 NLB:服务器级别的负载均衡方案 Nginx:反向代理 达到负载均衡. Redis:用作缓存(Redis 主从配置和参数详解 http://www. ...

  4. UVa712 S-Trees

    // UVa712 S-Trees // Rujia Liu // 题意:给一棵满二叉树,每一层代表一个01变量,取0时往左走,取1时往右走.给出所有叶子的值,以及一些查询(即每个变量的值),求最后到 ...

  5. TcxDBLookupCombobox 级联时第二级不显示正确内容的处理方法

    在使用两个级联的 TcxDBLookupCombobox 时,会出现这种情况:当第一级的内容变更后,第二级的控件在界面上显示的文本不变化,即使数据集已经通过 Properites.OnChange 事 ...

  6. 图片滚动js 实现图片无缝滚动

    在改章节中,我们主要介绍图片滚动的内容,自我感觉有个不错的建议和大家分享下 非常平滑的JS图片滚动特效代码,无缝循环,速度可自定义,鼠标悬停时停止.它的特点是JS和图片地址分离,这样做你就经易的从数据 ...

  7. Bump mapping的GLSL实现 [转]

    原文 http://www.cnblogs.com/CGDeveloper/archive/2008/07/03/1234206.html 如果物体表面细节很多,我们可以不断的精细化物体的几何数据,但 ...

  8. webqq 获得好友列表hash算法 获得最新hash的方法

    webqq获得好友列表的hash算法,大约每一个月中旬会变动一次.知道怎么获得他就能够了. js文件路径 http://web.qstatic.com/webqqpic/pubapps/0/50/eq ...

  9. iOS与日期相关的操作

    // Do any additional setup after loading the view, typically from a nib. //得到当前的日期 注意week1是星期天 NSDat ...

  10. ios开发——面试篇C语言精华

    面试篇C语言精华    1.面向过程:分析解决问题所需要的步骤,然后用函数把这些步骤一步一步实 现. 面向对象:直接描述客观世界的对象及其相互关系.现实世界中任何实体都 可以看作是对象,对象之间通过消 ...