第一篇:groovy对DSL的语法支持
引子
我们用一段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的语法支持的更多相关文章
- Bootstrap:Bootstrap_table第一篇:快速用bootstrap_table(支持参数)筛选并展示数据,固定表格前几列,实现表格单元格编辑
1.准备好css和js文件 <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstr ...
- Python编程笔记(第一篇)Python基础语法
一.python介绍 1.编程语言排行榜 TIOBE榜 TIOBE编程语言排行榜是编程语言流行趋势的一个指标,每月更新,这份排行榜排名基于互联网有经验的程序员.课程和第三方厂商的数量. 2.pytho ...
- 【ABAP系列】SAP ABAP7.40新语法简介第一篇
公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[ABAP系列]SAP ABAP7.40新语法简 ...
- 用仿ActionScript的语法来编写html5——第一篇,显示一张图片
第一篇,显示一张图片 一,代码对比 as代码: public var loader:Loader; public function loadimg():void{ loader = new Loade ...
- Groovy 与 DSL
一:DSL 概念 指的是用于一个特定领域的语言(功能领域.业务领域).在这个给出的概念中有 3个重点: 只用于一个特定领域,而非所有通用领域,比如 Java / C++就是用于通用领域,而不可被称为 ...
- 我的第一篇Markdown语法博客
这是我的第一篇使用markdown语法编写的博客 使用的编辑器为Sublime Text2 并且使用了sublog插件, sublog是一个开源项目 sublog 并且参考了作者的博客 AmongOt ...
- 我的第一篇Markdown博客
我的第一篇Markdown博客 这是我第一次用Markdown写博客,发现还是比较好用的,加上Marsedit也支持了Markdown的博客预览,博客园也加了Markdown的格式支持,就更加方便了, ...
- 微型 ORM 的第一篇 DapperLambda发布
引言:因为接触过多个ORM,但使用的时候都遇到了各自的一些不够理想的地方,从最早开始开始公司自己分装的,到后面用EF,以及Dapper和DapperExtensions 到现在用的FluentDat ...
- Scala语言笔记 - 第一篇
目录 Scala语言笔记 - 第一篇 1 基本类型和循环的使用 2 String相关 3 模式匹配相关 4 class相关 5 函数调用相关 Scala语言笔记 - 第一篇 最近研究了下scala ...
随机推荐
- Django 使用原生SQL
def dictfetchall(cursor): "将游标返回的结果保存到一个字典对象中" desc = cursor.description return [ dict(zip ...
- html常用的标签
很重要的: <form><input><section><option><textarea> <div> 很重要,重要的是相关的 ...
- Angularjs 初始化框架
bindJQuery(); publishExternalAPI(angular); jqLite(document).ready(function() { angularInit(document, ...
- Understanding CloudStack’s Physical Networking Architecture
Understanding and configuring the physical connections of a host in a CloudStack deployment can at f ...
- [刷题codeforces]651B/651A
651B Beautiful Paintings 651A Joysticks 点击可查看原题 651B是一个排序题,只不过多了一步去重然后记录个数.每次筛一层,直到全为0.从这个题里学到一个正确姿势 ...
- 如何同时启动多个Tomcat服务
在项目开发中,有时会需要同时启动多个Tomcat服务,如果直接启动多个的话,会报以下错误: Port busy xxxx java.net.SocketException: Unrecognized ...
- C#三种模拟自动登录和提交POST信息的实现方法
网页自动登录(提交Post内容)的用途很多,如验证身份.程序升级.网络投票等,以下是用C#实现的方法. 网页自动登录和提交POST信息的核心就是分析网页的源代码(HTML),在C#中,可以 ...
- 为joomla加入下拉菜单的方法
用 Joomla! 建站的大多数站长都须要在站点前台使用下拉菜单(dropdown menu),或者叫弹出菜单(slide menu),由于这样能够在有限的页面空间上公布很多其它的导航菜单,而且能够进 ...
- swift3.0 coredata 的使用
//swift3.0在语法上有很大的改变,以简单的增删改查为例,如下: //User类如下: import Foundation import CoreData extension User { @n ...
- Asp.Net MVC 3【Filters(过滤器)】
这里分享MVC里的Filters(过滤器),什么是MVC里的过滤器,他的作用是什么? 过滤器的请求处理管道中注入额外的逻辑.他们提供了一个简单而优雅的方式来实现横切关注点.这个术语是指所有对应用程序的 ...