클로저의 정의
클로저는 코드에서 전달 및 사용할 수 있는 독립된 기능의 중괄호 "{}"로 구분된 코드 블록이다. python의 람다(lambda)와 유사한 개념이라고 보면 된다. 클로저는 정의된 컨텍스트 내에서 모든 상수 및 변수에 대한 값을 캡쳐하고 레퍼런스를 저장할 수 있다.
클로저의 형태
클로저에는 크게 3가지 형태가 있다.
전역함수(Global functions)의 형태 : 이름이 있고 값을 캡쳐하지 않음.
중첩된 함수(Nested functions)의 형태 : 이름이 있고 둘러싸는 함수에서 값을 캡쳐할 수 있다.
클로저 표현식(Closure expressions) : 이름이 없고 경량 구문(lightweight syntax)으로 쓰이며 주변 컨텍스트에서 값을 캡쳐할 수 있다.
클로저와 함수의 차이
클로저는 함수와는 다르게 함수의 이름 정의가 따로 존재하지 않는다. 그러나 파라미터를 받아 처리하여 반환값을 내보낼 수 있다는 점에서 함수와 동일한 기능을 제공하고 있다. 이름이 따로 존재하지 않으므로 클로저는 익명 함수(Unnamed Closure)이다. 또한 우리가 일반적으로 정의하는함수도 클로저의 한 형태로, 이름이 있는 클로저(Named Closure)이다. 그러므로 함수와 클로저의 기능은 완전히 동일하나 형태의 차이만 있다고 보면 된다. (대표적으로 이름의 유무)
클로저의 파라미터는 중괄호 안에서 정의하며 함수와 마찬가지로 ->를 사용하여 반환 타입을 명시한다. 그러나 in 키워드를 써서 파라미터, 반환 타입의 영역과 실제 클로저 내에서 실행되는 코드를 분리한다.
그렇다면 여기서 드는 의문점!
클로저가 함수와 동일한 기능을 제공한다면 클로저 또한 함수와 같은 특성을 가지고 있지 않을까?
Swift는 함수를 1급 객체로 취급하고 있다.
일급 객체의 특성
- 객체가 런타임에도 생성이 가능해야 한다.
- 인자값으로 객체를 전달할 수 있어야 한다.
- 반환값으로 객체를 사용할 수 있어야 한다.
- 변수나 데이터 구조 안에 저장할 수 있어야 한다.
일급 객체로서의 함수
- "함수"를 변수나 상수에 할당할 수 있다.
- 함수의 인자 값으로 "함수"를 전달할 수 있다.
- 함수의 반환 타입으로 "함수"를 사용할 수 있다.
위의 일급 객체 특성에 따라 클로저에 대입하여 정리해보았다.
(1) "함수"를 변수나 상수에 할당할 수 있다.
let closure = { () -> () in
print("안녕")
}
let anotherClosure = closure // 정의된 클로저를 새 상수나 변수에 저장할 수 있음
(2) 함수의 인자 값으로 "함수"를 전달할 수 있다.
1) 함수를 파라미터로 받는 함수 정의
func closureTest(closure: () -> ()) {
print("프린트")
closure() // 함수 실행
}
2) 파라미터로 사용할 함수/클로저를 정의
func printFunction() { // 함수를 정의
print("프린트 function")
}
let printClosure = { () -> () in // 클로저를 정의
print("프린트 closure")
}
// 함수 또는 클로저를 파라미터로 넣으면서 실행
closureTest(closure: printFunction)
closureTest(closure: printClosure)
// - 실행결과 -
// 프린트
// 프린트 function
// 프린트
// 프린트 closure
3) 함수 실행할 때 클로저 형태로 전달
closureTest(closure: { () -> () in // closureTest 함수 실행할때 클로저 형태로 전달
print("프린트22")
})
// closure라는 아규먼트(인자)의 파라미터로 전달된 형태
// closureTest라는 함수에서 파라미터로 전달받은 클로저(함수)를 실행하면?
// 프린트22
// 보통은 아래와 같이 축약해서 쓰임
closureTest {
// code to execute
}
(3) 함수의 반환 타입으로 "함수"를 사용할 수 있다.
func returnClosure() -> () -> () {
let closure = { () -> () in
print("closure return")
}
return closure
}
// MARK: - 위의 코드 축약 -
func returnClosure() -> () -> () {
return { () -> () in
print("closure return")
}
}
let closure2 = returnClosure() // closure2 상수의 타입이 () -> () 함수 타입인 것을 확인할 수 있음.
closure2() // closure return 출력
클로저의 사용 이유
함수를 실행할때 파라미터로 클로저를 정의하면서 바로 전달할 수 있음. (그렇기 때문에 이름이 필요없음)
참고
https://docs.swift.org/swift-book/LanguageGuide/Closures.html#