转载

Groovy进阶之函数、闭包和类

上一篇文章 Groovy入门之语法和变量定义 重点记录的是Groovy的语法以及变量,这一篇文章继续学习Groovy的一些相关知识点。本文的重点是函数和闭包、类和对象,知识点涉及到与Java一样的地方在文章中就不做介绍了,重点将一些与Java不同的地方。另外如果有人接触过JavaScript,相信多数也了解JavaScript中闭包这个概念,但是Groovy中闭包与JavaScript闭包是两个完全不同概念。

函数与闭包

函数

有些人可能对函数和方法的叫法一直不太清楚。事实上没有本质区别,在面向过程的语言中一般称为函数,在函数式编程中一般都叫做函数。方法的一般是类的方法,在某一个类中定义的称之为方法。

1.在Groovy中除非指定了确定的返回类型,void也可以作为返回值的一种,否则定义函数必须加上关键字def。

String getString(){
    return "hello world"
}
 
defgetDef(){
    return "hello world"
}
 
void printSomething(){
    println "hello worlld"
}
 
//错误的定义,编译可以通过,但是运行时报错
//getString(){
//    return "hello world"
//}

2.在定义函数需要传参时可以不设置设置参数的类型,默认是Object类型的,如果用def关键字设置参数类型,事实上也是使用的Object定义参数的。

Groovy进阶之函数、闭包和类

defprintSomething01(param){
    printlnparam
}
 
defprintSomething02(int param){
    printlnparam
}
 
defprintSomething03(defparam){
    printlnparam
}

3.在调用函数时,如果所定义的函数有参数,在使用的时候可以不使用括号,但是必须得传入参数,参数与函数名以空格隔开。

如果不出入参数必须添加括号,否则代码编译可以通过,但是运行时会出错,会将函数误认为是一个属性。

如果所定义的函数没有参数,在调用的时候必须添加括号,否则运行出错,会将函数误认为是一个属性。

函数调用的时候参数的个数必须匹配,否则也会报错,提示没有定义该函数,如果单个参数除外,可以不用输入参数,系统默认赋值null。

defprintSomething(param01,param02){
    printlnparam01+param02
}
 
printSomething ("hello","world")//helloworld
printSomething "hello","world"//helloworld
 
//参数个数不对,报错
//printSomething ("hello")
 
defprintOne(param){
    printlnparam
}
printOne()//null

4.函数可以有返回值,如果有显示地使用return关键字,则返回return指定的返回值,其后面的语句不再执行。

如果没有显式地使用return关键字,则返回函数最后一行语句的运行结果。

如果使用void关键字代替def关键字定义函数,则函数的返回值将为null。

defprintSomething(){
    return "hello"
    println "world"
}
printlnprintSomething()//hello
 
defprintSomething01(){
    "hello world"
    1
}
printlnprintSomething01()//1
 
defprintSomething02(){
    1
    "hello world"
}
printlnprintSomething02()//hello world

5.支持函数重载,当参数个数不同时,函数名称可以同名。

defprintSomething(param){
    printlnparam
}
 
defprintSomething(param01,param02){
    printlnparam01+" "+param02
}
 
printSomething("hello")
printSomething("hello","world")

6.函数内不可以访问函数外的变量

int m=1
def n="hello"
//error
defprintSomething(){
    println m//error
    println n//error
}
printSomething()

7.Groovy支持不定长参数。

defprintSomething(... params) {
    println(params[0])
}
 
printSomething("hello")
printSomething("hello","world")

8.函数可以赋值给其它函数,使用语法标记&将函数赋予新的函数。

defprintSomething() {
    println("hello world")
}
 
//printSomething不可以加括号
defprintHello=this.&printSomething
 
printHello()//hello world
printSomething()//hello world

闭包

在Javascript中闭包的定义:有权访问另外一个函数作用域中的变量的函数。

Groovy中闭包是这么定义的:可以用作函数参数和方法参数的代码块。可以把这个代码块理解为一个函数指针。

闭包的定义格式:

defxxx = { params -> code }
//或者
defxxx={code}

在这里可以看出来这里的闭包跟JavaScript中以字面量形式定义对象格式类似。

var obj={username:"admin"}
console.log(obj.username);

从这里也可以看出来Groovy中闭包表示形式和闭包跟JavaScript中所讲解的闭包是完全不同的。

1.闭包可以访问外部的变量,记住一点方法是不能访问外部变量的。

defstr="hello world"
 
defclosure={
    printlnstr
}
 
closure()//hello world

2.闭包调用的方式有两种,闭包.call(参数)或者闭包(参数),在调用的时候可以省略圆括号。

defclosure = {
    param -> printlnparam
}
 
closure("hello world")
closure.call("hell call")
closure "hello world"

3.闭包是有返回值的,默认最后一行语句就是该闭包的返回值,如果最后一行语句没有不输入任何类型,闭包将返回null。

defclosure = {
    println "hello world"
    return "I'm callback"
}
//hello world
//I'm callback
printlnclosure()
 
defnoReturn={
    println "hello world"
}
//hello world
//null
printlnnoReturn()

4.闭包可以有参数,如果没有定义参数,会有一个隐式的默认参数it,如果没有参数可以将[参数]和[->]省略。

如果存在参数,在[->]之前的就是参数,如果只有一个参数,参数可以省略。

闭包中参数名称不能与闭包内或闭包外的参数名重名

defclosure={
    println "hello $it"
}
closure("admin")
 
defclosure={
    param01,param02,param03->printlnparam01+param02+param03
}
closure "hello","world","ok"
 
defclosure={
    printlnit
}
closure "hello world"
 
//编译时就不通过
//def param
//def closure={
//    param->println param
//}

5.闭包可以作为一个参数传递给另一个闭包,也可以在闭包中返回一个闭包。

deftoTriple = { n -> n * 3 }
defrunTwice = { a, c -> c(c(a)) }
printlnrunTwice(5, toTriple)//45
 
deftimes = { x -> { y -> x * y } }
printlntimes(3)(4)//12

6.闭包的一些快捷写法,当闭包作为闭包或方法的最后一个参数,可以将闭包从参数圆括号中提取出来接在最后。

如果闭包中不包含闭包,则闭包或方法参数所在的圆括号也可以省略。

对于有多个闭包参数的,只要是在参数声明最后的,均可以按上述方式省略。

defrunTwice = { a, c -> c(c(a)) }
printlnrunTwice(5, { it * 3 }) //45 usual syntax
printlnrunTwice(5) { it * 3 } //45
 
defclosure = {
    param -> printlnparam
}
closure "hello world"
 
defrunTwoClosures = { a, c1, c2 -> c1(c2(a)) }
//when more than one closure as last params
assert runTwoClosures(5, { it * 3 }, { it * 4 }) == 60 //usual syntax
assert runTwoClosures(5) { it * 3 } { it * 4 } == 60 //shortcut form

7.闭包接受参数的规则,会将参数列表中所有有键值关系的参数,作为一个map组装,传入闭包作为调用闭包的第一个参数。

def f= {m, i, j-> i + j + m.x + m.y }
println f(6, x:4, y:3, 7)//20

8.如果闭包的参数声明中没有list,那么传入参数可以设置为list,里面的参数将分别传入闭包参数。

def c = { a, b, c -> a + b + c }
deflist = [1, 2, 3]
println c(list) // 6

类和对象

Groovy类与Java类似,在字节码级都被编译成Java类,由于其在定义变量上面的灵活性,所以在新建一个Groovy类时还是有一些不同的,增加了许多灵活性。由于Groovy是松散型语言,它并不强制你给属性、方法参数和返回值定义类型。如果没有指定类型,在字节码级别会被编译成Object。在定义类的属性时不用刻意加上权限修饰符,默认就是public的。

class Book{
    deftitle
    String author
 private int price
 
    public Book(title){
        this.title=title
    }
    boolean order(int isbn){
        true
    }
    deftitle(){
        "Booke Title"
    }
}
 
Bookbook=new Book("Hello Groovy")
book.order(1001)
 
book.title//获取属性
book.title()//访问方法

如果我们将Book类看做是一个JavaBean,事实上Groovy在编译完成后会自动帮助我们生成getter与setter方法,但是私有属性除外也就是说price属性我们不能使用getter与setter方法。

Bookbook=new Book("Hello Groovy")
printlnbook.getTitle()//Hello Groovy
 
book.setTitle("New Groovy")
printlnbook.getTitle()//New Groovy
 
printlnbook.title////New Groovy

在Groovy中类名和文件名并不需要严格的映射关系,我们知道在Java中主类名必须与文件同名,但是在Groovy中一个文件可以定义多个public类。

在Groovy中可以定义与任何类不相关的方法和语句,这些方法通常称为独立方法或者松方法。

class Hello{
    public static String hello(){
        return "hello"
    }
}
class World{
    public static String world(){
        return "world"
    }
}
 
printlnHello.hello()+World.world()
 
defhelloWorld(){
 return "hello world"
}

上面一个文件名定义为Structure.groovy,在这个文件中包含了类的定义和独立方法声明,它编译之后会发生什么呢。首先会生成一个与文件同名的class文件。所有的松语句都集中在run方法中,并且run方法被该类的main方法调用。独立方法被编译成了类的静态方法。与Java相似,每一个独立的类都会被编译成一个单独的class文件。因此编译Structure.groovy文件最后会被编译成Hello.class、World.class和Structure.class。上面一个文件名定义为Structure.groovy,在这个文件中包含了类的定义和独立方法声明,它编译之后会发生什么呢。首先会生成一个与文件同名的class文件。所有的松语句都集中在run方法中,并且run方法被该类的main方法调用。独立方法被编译成了类的静态方法。与Java相似,每一个独立的类都会被编译成一个单独的class文件。因此编译Structure.groovy文件最后会被编译成Hello.class、World.class和Structure.class。

本文地址: www.sunnyang.com/522.html

小结

有关Groovy的学习就先到这里,有关Groovy基础语法的讲解可以参看 Groovy入门之语法和变量定义 这篇博文,两篇文章主要还是偏重中一些基本使用,为的是可以更好的理解应用Android Studio的Gradle工具。笔记的记录基本都是通过浏览别人博客以及《Java脚本编程:语言、框架与模式》这本书,由于个人能力所限,文章中难免有错误疏漏之处,如若发现还望及时指出以求共同进步。

参考资料

Groovy学习笔记之块、闭包与函数

深入理解Android之Gradle

Groovy基础——Closure(闭包)详解

groovy-闭包

Java脚本编程:语言、框架与模式

原文  http://www.sunnyang.com/522.html
正文到此结束
Loading...