找回密码
 立即注册
首页 业界区 安全 【Groovy】函数、闭包、泛型

【Groovy】函数、闭包、泛型

醋辛 6 天前
1 函数

1.1 无参函数

​    1)常规调用
  1. void myFun() {
  2.     println("myFun")
  3. }
  4. myFun() // 打印: myFun
复制代码
​    2)字符串声明函数
  1. void "myFun"() {
  2.     println("myFun")
  3. }
  4. myFun() // 打印: myFun
复制代码
​    3)字符串调用函数
  1. void myFun() {
  2.     println("myFun")
  3. }
  4. "myFun"() // 打印: myFun
复制代码
1.2 有参函数

​    1)常规调用
  1. void myFun(Integer num, String str) {
  2.     println("$num, $str")
  3. }
  4. myFun(5, "abc") // 打印: 5, abc
复制代码
​    在不引起歧义的情况下,可以省去小括号,如下。
  1. void myFun(Integer num, String str) {
  2.     println("$num, $str")
  3. }
  4. myFun 5, "abc" // 打印: 5, abc
复制代码
​    2)入参指定默认值
  1. void myFun(String str = "abc") {
  2.     println(str)
  3. }
  4. myFun() // 打印: abc
复制代码
1.3 有返回值函数
  1. def add(int a, int b) {
  2.     return a + b
  3. }
  4. def c = add(3, 5)
  5. println(c) // 打印: 8
复制代码
1.4 可变长参数函数

​    1)常规调用
  1. void myFun(String... params) {
  2.     for (str in params) {
  3.         println(str)
  4.     }
  5. }
  6. myFun("aa", "bb", "cc") // 打印: aa、bb、cc
复制代码
​    说明:函数的可变长参数个数最多为 1 个。
​    2)使用数组接收可变长参数
  1. void myFun(String... params) {
  2.     String[] arr = params
  3.     println(arr.size())
  4. }
  5. myFun("aa", "bb", "cc") // 打印: 3
复制代码
​    3)将数组传给可变长参数函数
  1. void myFun(String... params) {
  2.     println(params.size())
  3. }
  4. String[] arr = ["aa", "bb", "cc"]
  5. myFun(*arr)  // 打印: 3
  6. myFun("xx", *arr, "yy")  // 打印: 5
复制代码
2 闭包

​    Groovy 中的闭包与 Java 中匿名函数(即没有名字的函数)有些类似,并且也提供了类似 Lambda 表达式的写法(详见 → Java 中 Lambda 表达式总结、Kotlin 中 Lambda 表达式)。
2.1 闭包的创建

2.1.1 通过 new 创建闭包
  1. Closure myFun = new Closure(null) {
  2.     int call(int a, int b) {
  3.         return a + b
  4.     }
  5. }
  6. def res = myFun(3, 5)
  7. println(res) // 打印: 8
复制代码
2.1.2 通过 {} 创建闭包

​    1)无参闭包
  1. def myFun = {
  2.     println("myFun")
  3. }
  4. myFun() // 打印: myFun
复制代码
​    2)有参闭包
  1. def myFun = { String str ->
  2.     println("myFun, $str")
  3. }
  4. myFun("abc") // 打印: myFun, abc
复制代码
​    闭包的入参类型可以省去,如下。
  1. def myFun = { str ->
  2.     println("myFun, $str")
  3. }
  4. myFun("abc") // 打印: myFun, abc
复制代码
​    当闭包入参个数只有一个时,可以省去,引用时使用 it 替代,如下。
  1. def myFun = {
  2.     println("myFun, $it")
  3. }
  4. myFun("abc") // 打印: myFun, abc
复制代码
​    3)有返回值闭包
  1. def myFun = { a, b ->
  2.     return a + b
  3. }
  4. def res = myFun(3, 5)
  5. println(res) // 打印: 8
复制代码
2.2 闭包对象封装函数

​    本节主要介绍使用闭包对象封装一个函数。
2.2.1 使用 {} 封装函数
  1. void test() {
  2.     println("test")
  3. }
  4. def myFun = { test() }
  5. myFun() // 打印: test
复制代码
2.2.2 使用 this.& 封装函数

​    1)无参函数
  1. void test() {
  2.     println("test")
  3. }
  4. def myFun = this.&test
  5. myFun() // 打印: test
复制代码
​    2)有参函数
  1. void test(int a, String b) {
  2.     println("test, $a, $b")
  3. }
  4. def myFun = this.&test
  5. myFun(123, "abc") // 打印: test, 123, abc
复制代码
​    3)有返回值函数
  1. def test(int a, int b) {
  2.     return a + b
  3. }
  4. def myFun = this.&test
  5. def res = myFun(3, 5)
  6. println(res) // 打印: 8
复制代码
2.3 函数参数是闭包

​    1)闭包无参
  1. void outFun(Closure closure) {
  2.     closure()
  3. }
  4. outFun({
  5.     println("inFun") // 打印: inFun
  6. })
复制代码
​     当函数入参的最后一个参数是闭包时,可以将 {} 移到 () 外面(该方式称为尾随 Lambda 表达式);在不引起歧义的情况下,可以省去 (),如下。
  1. void outFun(Closure closure) {
  2.     closure()
  3. }
  4. outFun {
  5.     println("inFun") // 打印: inFun
  6. }
复制代码
​    2)闭包有参
  1. void outFun(Closure closure) {
  2.     closure("abc")
  3. }
  4. outFun { a ->
  5.     println(a) // 打印: abc
  6. }
复制代码
​    当闭包入参个数只有一个时,可以省去,引用时使用 it 替代,如下。
  1. void outFun(Closure closure) {
  2.     closure("abc")
  3. }
  4. outFun {
  5.     println(it) // 打印: abc
  6. }
复制代码
​    3)闭包有返回值
  1. void outFun(Closure closure) {
  2.     def res = closure(3, 5)
  3.     println(res)
  4. }
  5. outFun { a, b ->
  6.     a + b // 打印: 8
  7. }
复制代码
2.4 通过字符串调用对应函数
  1. void myFun(String str, int num) {
  2.     println("myFun, $str, $num")
  3. }
  4. void test(String funName, String str, int num) {
  5.     def method = this.&"$funName"
  6.     method(str, num)
  7. }
  8. test("myFun", "abc", 3) // 打印: myFun, abc, 3
复制代码
3 泛型函数

​    泛型的类型检查只存在于编译阶段,在源代码编译之后,不会保留任何关于泛型类型的内容,即类型擦除。
3.1 简单泛型函数

​    1)单泛型参数
  1. <T> void myFun(T param) {
  2.     println(param)
  3. }
  4. myFun(123)  // 打印: 123
  5. myFun("abc")  // 打印: abc
  6. myFun(true)  // 打印: true
  7. myFun(null)  // 打印: null
复制代码
​    2)多泛型参数
  1. <R, T, S> R myFun(T a, S b, R c) {
  2.     println("$a, $b")
  3.     return c
  4. }
  5. def res = myFun("abc", 123, true) // 打印: abc, 123
  6. println(res) // 打印: true
复制代码
3.2 类中泛型函数
  1. class MyClass<T> {
  2.     void myFun(T a) {
  3.         println(a)
  4.     }
  5. }
  6. def c1 = new MyClass<String>()
  7. c1.myFun("abc") // 打印: abc
  8. def c2 = new MyClass<Integer>()
  9. c2.myFun(123) // 打印: 123
复制代码
3.3 抗变、协变和逆变

​    Groovy 中不存在 Java 和 Kotlin 中的抗变、协变和逆变现象(详见 → 【Kotlin】函数)。
​    如下,Integer 是 Number 的子类,Number 引用可以指向 Integer 对象,并且 Data 引用可以指向 Data 对象,Data 引用也可以指向 Data 对象,还可以访问、修改对象的泛型变量,这在 Java 和 Kotlin 中是不允许的。
  1. class Data<T> {
  2.     T value
  3.     Data(T value) {
  4.         this.value = value
  5.     }
  6. }
  7. Data<Integer> data1 = new Data<Integer>(1)
  8. Data<Number> data2 = data1
  9. data2.value = 10f
  10. println(data2.value) // 打印: 10.0
  11. Data<Number> data3 = new Data<Number>(1.5f)
  12. Data<Integer> data4 = data3
  13. data4.value = 15
  14. println(data4.value) // 打印: 15
复制代码
3.4 泛型的界

​    Groovy 泛型中,可以为其指定上界。
​    1)单上界
  1. class Data<T extends Number> {
  2.     T value
  3.     Data(T value) {
  4.         this.value = value
  5.     }
  6. }
  7. Data<Integer> data1 = new Data<Integer>(1)
  8. Data<String> data2 = new Data<String>("abc") // 运行错误, 指定了上界为Number
复制代码
​    2)多上界
  1. class A {}
  2. interface B {}
  3. class C extends A implements B {}
  4. class Data<T extends A & B> {
  5.     T value
  6.     Data(T value) {
  7.         this.value = value
  8.     }
  9. }
  10. def data = new Data(new C())
复制代码
3.5 运行时检查泛型类型

​    Kotlin 中可以通过 inline 和 reified 关键字实现泛型类型检查(详见 → 【Kotlin】函数),它在编译阶段实现。
​    Groovy 是动态类型语言,类型检查在运行时进行,可以通过反射来实现类似的功能,如下。
  1. <T> boolean isType(Class<T> type, value) {
  2.     return type.isInstance(value)
  3. }
  4. println(isType(Integer, "abc")) // 打印: false
  5. println(isType(String, "abc"))  // 打印: true
复制代码
​    声明:本文转自【Groovy】函数、闭包、泛型。

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册