본문 바로가기

Script/Groovy

10. Closures

 
그루비 클로저는 이름없는 메서드에 대한 포인터에 해당하며 함수를 함수 포인터에 저장하는것에 불과하다.
 
클로저 정의는 중괄호 { } 를 이용해서 하며 호출시는 
 
<클로저명>.call() 또는 일반 메서드 처럼 <클로저명>( ) 으로 실행할 수 있다.
 
Groovy 에서는 아주 많은 부분에서 클로저를 사용하기 때문에 반드시 알고 활용할 수 있어야 한다.
 
 
 
Basic
 
def c = {}
 
println c.class.name
Test$_run_closure1
def exMap = [:]
 
def exClosure = {
println "Hello"
}
 
exMap.closureProp = exClosure
exMap.closureProp()
Hello
 
기본적으로 함수와 비슷하게 사용되지만 Argument 를 넣고자 하면 아래와 같이 해야 한다.
 
def sayHello = {
println "Hello"
}
 
def sayHelloWithArg = { name ->
println "Hello ${name}"
}
 
sayHello()
sayHelloWithArg('Dkim')
 
//Closure 를 인자로 받는 함수 제작
def timesTen(num,closure) {
closure(num*10)
}
 
//Closure 를 함수에 전달, it 을 사용하면 편리함, () 생략 가능
timesTen(10,{num-> println num})
timesTen(10,{println it})
timesTen 10,{println it}
Hello
 
Hello Dkim
 
100
100
100
 
 
 
Closure Parameter
 
파라미터 넣는 부분은 파라미터가 하나인 경우는 it 을 활용하고
 
아니면 -> 오퍼레이터로 여러 인자를 넣을 수 있다.
 
def fooWithIt = {
   println it
}
 
fooWithIt ('foo1')
 
def fooWithParam = { name ->
   println "${name}"
}
 
fooWithParam('foo2')
 
def fodWithMultiParam = { first, last ->
   println "Hello ${first} ${last}"
}
 
fodWithMultiParam ("Daeung","Kim")
 
foo1
foo2
Hello Daeung Kim
 
 
 
Collections Method
 
Collection 데이터 타입의 메서드에는 Closer 를 인자로 받는 많은 메서드가 있다.
 
예를 들어 List 의 경우 each, eachWithIndex, findAll, .. 등의 메소드가 있다.
 
def nums =[1,2,3,4,5]
 
nums.each {println it}
 
nums.eachWithIndex{ int num, int index ->
println "${index} : ${num}"
}
 
def days = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat']
List weekend = days.findAll {
it.startsWith('S')
}
 
println weekend
 
 
def numsTimesTen = nums.collect {num -> num * 10}
println numsTimesTen
1
2
3
4
5
 
0 : 1
1 : 2
2 : 3
3 : 4
4 : 5
 
[Sun, Sat]
 
[10, 20, 30, 40, 50]
 
 
Curry Methods
 
Curry 메서드는 클로저 를 랩핑하는 메서드로 클로저 메서드에 인자값을 특정하는 경우 유용하다.
 
말이 어려운데 사실 Default 값을 넣어놓은 클로저 메서드 정도로 이해하면 되겠다.
 
def log = { String type, Date createOn, String msg ->
println "$createOn [$type] - $msg"
}
 
log("Debug", new Date(), "First Msg")
 
def debugLog = log.curry("Debug")
 
debugLog(new Date(),"Curry First Msg")
debugLog(new Date(),"Curry Second Msg")
 
def specifiedPersonLog = log.rcurry("Im The Person")
specifiedPersonLog("ERROR", new Date())
 
Mon Oct 14 15:53:04 KST 2019 [Debug] - First Msg
Mon Oct 14 15:53:05 KST 2019 [Debug] - Curry First Msg
Mon Oct 14 15:53:05 KST 2019 [Debug] - Curry Second Msg
Mon Oct 14 15:55:18 KST 2019 [ERROR] - Im The Person
 
 
Closure Scope & Delegate
 
 
closer 내부에는 this 와 owner 와 delegate 라는 속성이 들어 있는데 위와 같이 정의된다.
 
this 는 클로저가 정의된 클래스를 가리키며 owner 는 클로저가 정의된 오브젝트를 가리키지만
 
delegate 는 자신을 call 한 third party 오브젝트를 가리킨다.
 
보통은 owner 와 delegate 는 일치하지만 owner 객체에서 자신을 call 할 수 있는 메서드가 없다면
 
외부에서 자신을 call 할 수 있는 메서드를 찾아 사용해버린다.
 
class ScopeDemo {
  def outerClosure = {
    println this.class.name
    println owner.class.name
    println delegate.class.name
 
    def nestedClosure = {
      println this.class.name // 클로저가 정의된 클래스
      println owner.class.name // 클로저가 정의된 오브젝트
      println delegate.class.name // Delegate 는 기본적으로 Closer 를 호출한 Object
    }
 
    nestedClosure()
  }
}
 
def demo = new ScopeDemo()
demo.outerClosure()
ScopeDemo
ScopeDemo
ScopeDemo
ScopeDemo
ScopeDemo$_closure1
ScopeDemo$_closure1
 
그래서 다음과 같이 StringBuffer 객체가 Delegate 객체로 지정되어 writer 클로저가 동작하고 
 
결과가 StringBuffer 객체에 저장되게 된다.
 
def writer = {
append 'Dan'
append " Lives In KangNam"
}
 
def sb = new StringBuffer()
writer.delegate = sb
 
writer()
 
println sb
Dan Lives In KangNam
 
 

'Script > Groovy' 카테고리의 다른 글

12. Exception  (0) 2020.01.21
11. Conditional Statement  (0) 2020.01.21
09. Collection  (0) 2020.01.21
08. RegExp  (0) 2020.01.21
07. String  (0) 2020.01.21