rss· 投稿· 设为首页· 加入收藏· 繁體版
当前位置: 火魔网 » 程序开发 » Groovy

Groovy基础(笔记七)

8. 闭包
  8.1 闭包的语法结果如下,如果没有参数,那么参数列表和 ->可以缺省.比如下面的clos引用的闭包,没有参数只有一个执行语句,它可以被clos调用call方法来执行.
 ----------------------------------------------------
 {逗号分隔的参数列表 -> 执行语句块}
 def clos ={println "Hello World"}
 clos.call()
 ----------------------------------------------------
 我们也可以加入参数,比如下面的语句:
 ----------------------------------------------------
 def clos = {param -> println "Hello ${param}"}
 clos.call('pwy')   // 'Hello pwy'
 clos.call('tracy')   // 'Hello tracy'
 clos('pwy')    // 'Hello pwy', call可以是缺省的
 ----------------------------------------------------
 闭包中有一个默认的隐含参数it可以被调用,如:
 ----------------------------------------------------
 def clos = {println "Hello ${it}"}
 clos.call('pwy')   // 'Hello pwy'
 clos.call('tracy')   // 'tracy'
 clos('pwy')    // 'Hello pwy' call省略
 ----------------------------------------------------
 闭包可以引用它定义之前的已经定义的变量,下面的变量name是在闭包clos定义之前定义的,所以clos被调用的时候可以引用name的值,它的值初始化为'pwy'.
 ----------------------------------------------------
 def name ='pwy'
 def clos = {param -> println "${name} ${param}"}
 clos.call('handsome')   // 'pwy handsome'
 name = '2Bing' 
 clos.call('handsome')   // '2Bing handsome'
 
 def test(col){
     def name = 'others'   // 此处局部变量name 是在闭包clos定义之后定义的,所以clos不能引用它的值
     col.call('handsome') 
 }
 
 test(clos)    // '2Bing handsome'
 ----------------------------------------------------
 我们可以调用一个带有clos参数的方法,groovy提供了简单的方式使得代码更容易阅读,参数clos从参数列表中移除,放到方法括号后面,所以下面两种形式都是对的.
 ----------------------------------------------------
 test(clos)    // 参数闭包clos在方法中
 test() clos    // 参数闭包clos在方法外
 ----------------------------------------------------
 闭包通常应用于集合,我们循环集合中的所有元素,然后对每个元素调用闭包.比如,所有的数值类型对象都支持upto方法 void upto(Number to,Closure closure)
 我们可以这样使用它, 1.toto(10) {p->...}, 然后每次迭代默认参数值分别为1,2,3....10.
 ----------------------------------------------------
 def factorial = 1
 1.upto(5) {num -> factorial*=num} // 从1开始迭代到5,每次变量factorial分别乘以闭包默认参数1,2,3,4,5将值返回赋给本身
 println "Factorial(5):${factorial} " // 打印输出 "Factorial(5):120"
 ----------------------------------------------------
  8.2 闭包、集合、字符串
 一些List,Map,String对象的方法可以接受闭包作为参数,这种闭包和集合的混合方式给groovy提供了解决通用程序问题的比较优雅的解决方案.比如each方法的使用:
 void each(Closure closure) 用来循环List,Map,String,并对每个元素使用闭包.
 ----------------------------------------------------
 [1,2,3,4].each{ print it}  // 1234     
 ['pwy':'handsome','2Bing':'beautiful'].each{ print it}  // pwy=handsome2Bing=beautiful
 ['pwy':'handsome','2Bing':'beautiful'].each{ println "${it.key} maps to: ${it.value}" }  // pwy maps to: handsome 2Bing maps to: beautiful 
 'pwy'.each{print it}   //  pwy
 ----------------------------------------------------
 find方法从集合中查找匹配某些条件的第一个值,在闭包中指定的被集合元素匹配的条件必须是某个Boolean表达式,find方法返回第一个找到的值,如果没找到则返回null
 ----------------------------------------------------
 def value = [1,3,5,7,9].find{element -> element>6}
 println "Found: ${value}"  // "Found:7"

 def value2 = [1,3,5,7,9].find{element -> element >10}
 println "Found: ${value2}"  // "Found:null"
 
 def value3 = ['pwy':27,'2Bing':28].find{element -> element.value>27} 
 println "Found: ${value3}"  // "Found:2Bing=28" 注意当我们对map对象使用find方法时,参数和返回的值都是一个Map.Entry对象.
 ----------------------------------------------------
 findAll方法可以从集合中查找出匹配到指定条件的所有元素,并将结果作为list返回 List findAll(Closure closure)
 ----------------------------------------------------
 def value = [1,3,5,7,9].find{element -> element>6}
 value.each{print it}   // "79"
 ----------------------------------------------------
 any方法通过循环迭代集合中的所有元素,检查是否至少有一个元素符合闭包中的boolean表达式,如果检查是这样返回true,否则返回false.
 every方法通过循环迭代集合的所有元素,检查是否每个元素都符合闭包中的boolean表达式,如果检查是这样返回true,否则返回false.
 boolean any(Closure closure) 
 boolean every(Closure closure)
 -----------------------------------------------------
 def value = [1,3,5,7,9].any{element -> element>8} 
 println "Found: ${value}"  // "Found:true"
 def value2 = [1,3,5,7,9].every{element -> element>3} 
 println "Found: ${value2}"  // "Found:false"     
 -----------------------------------------------------
 collect方法循环迭代集合中的所有元素,通过闭包改变每个元素的值放入一个新的List中返回. List collect(Closure closure)
 -----------------------------------------------------
 def list = [1,3,5].collect{element -> return element*element} // return 可以省略
 println "list: ${list}"   // [1,9,25]
 def list2 = (0..5).collect{element -> element+1}  
 println "list2: ${list2}"  // [1,2,3,4,5,6]
 ------------------------------------------------------
 以上例子中,方法collect可以用于范围对象,这是允许的因为Range接口继承与List接口,所以可以作为list来使用.
 最后一个是inject方法,它有一个初始值参数,inject方法循环迭代一个List,并使用闭包处理第一个元素,将返回结果赋值给下个循环迭代的初始值参数,直到循环结束,
 返回最后的计算结果
 Object inject(Object obj,Closure closure)
 ------------------------------------------------------
 def number = [1,2,3,4].inject(1){previous,element ->  previous*element}
 println "number: ${numbers}"
 ------------------------------------------------------
  8.3 其他的闭包的特征
 由于闭包是一个对象,它可以作为一个方法的参数.下面的filter方法带有两个参数,一个list对象和一个闭包对象.该方法可以查询list中所有符合闭包指定条件的元素.
 ------------------------------------------------------
 def filter (list,predicate){
  return list.findAll(predicate)
 }
 def idEven ={x -> return (x%2==0)}
 def isOdd ={x -> return ! isEven(x)}
 def table = [1,2,3,4,5,6]
 def evens = filter(table,isEven)  
 println "evens: ${evens}"  // [2,4,6]
 
 def odds = fileter(table,isOdd)
 println "odds: ${odds}"   // [1,3,5]
 ------------------------------------------------------
 闭包还可以作为其他闭包的参数,下面的例子中先定义了一个闭包tabkeWhile,它有两个参数:闭包predicate,和list,这个方法循环迭代list中的每个元素,将符合闭包条件  的元素放入一个集合result中,直到找到不符合条件的元素,结束循环,返回reuslt集合.
 ------------------------------------------------------
 def takeWhile ={predicate,list ->
   def result =[]
   for (element in list){
    if(predicate(element)){
     result << element
    } else {
     return result
    }
   }
   }
 
 def table1 =[11,12,13,14,15,16]
 def table2 =[11,13,15,16,18]
 def idEven ={x -> return (x%2==0)}
 def isOdd ={x -> return ! isEven(x)}
 def evens = takeWhile.call(isEven,table1)
 println "evens: ${evens}"  // [12]
 def odds = takeWhile.call(isOdd,table2)
 println "odds: ${odds}"   // [11,13,15]
 -------------------------------------------------------

顶一下
(0)
踩一下
(0)