티스토리 뷰

Swift

클로저 표현 (Closure Expressions)

강경 2021. 3. 23. 20:16
728x90
반응형

이전에 클로저에 대해 어느정도 정리를 해뒀었지만, 통합하여 제대로 정리해보려 합니다..!
(아래 링크는 사실 무시하셔도 전혀 상관없습니다.. 블로그 초창기 공부하려고 시도했던 흑역사에요😭)
Closure - 1
Closure - 2
Closure - Capturing Values
Closure - 3


 

Closures are self-contained blocks of functionality

클로저는 기능을 수행하는 코드블럭을 뜻합니다.
우리가 흔히 알고있는 함수(메서드)역시 클로저의 일종이라고 볼 수 있어요😮

 

클로저는 보통 3가지의 형태를 가집니다.

  1. Global 함수: 이름이 있고 어떤 값도 캡쳐(?)하지 않는 클로저
  2. Nested 함수: 이름이 있고 관련한 함수로 부터 값을 캡쳐(?) 할 수 있는 클로저
  3. Closure Expressions: 경량화 된 문법으로 쓰여지고 관련된 문맥(context)으로부터 값을 캡쳐(?)할 수 있는 이름이 없는 클로저
    (캡쳐(?)라는 표현이 낯설겠지만, 자세한건 다다음 챕터에 다뤄보도록 하겠습니다😅)

이렇듯, 클로저는 어떤 상수나 변수의 참조를 캡쳐(capture)해 저장할 수 있는 특징을 가집니다.
위의 1번과 2번, 전역함수(global functions)중첩함수(nested function)는 클로저의 특별한 경우이므로,
클로저 표현(Closure Expressions)에 대해 먼저 다뤄보겠습니다!

 

클로저 표현 (Closure Expressions)

클로저 표현은 코드의 명확성과 의도를 유지하면서 문법을 축약하는, 다양한 문법의 최적화 방법을 제공합니다.

 

클로저의 모양

let simpleClosure = {

}

이렇듯, 그냥 코드블럭"{}"을 나타내는 겁니다..!!
이름대로 매우 심플하게 나타낼 수 있어요😲

 

{ (parameters) -> return type in
    statements
}

이런 식으로, 파라미터와 반환타입을적어 마치 이름이 없는 함수의 형태로도 사용할 수 있습니다!
(함수 자체도 클로저의 한 형태니까요😁)

 

쓰임새

그러면, 클로저는 어떻게 쓰이는지 한번 볼까요~~?

 

let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]

자, 여기 이름이 모여있는 배열이 있어요.
이 이름들을 알파벳 역순서로 재배치 하고싶다고 가정을 해봅시다.
"Ewa", "Daniella", "Chris", "Barry", "Alex" 이 순서로 말이죠!

(굳이..?)

var reversedNames = names.sorted(by: backward)

재배치를 해주기 위해 배열(Array)에서 사용할 수 있는 Swift표준라이브러리 메서드인sorted()를 이용하였습니다!
근데, 이 함수는 클로저를 파라미터로 받고있어요(by: 이런 형태로 말이죠!)
이제 우리는 backward()라는 클로저를 정의해주어야겠죠?😱

 

func backward(_ s1: String, _ s2: String) -> Bool {
    return s1 > s2 // 두 string을 비교해서, 알파벳 순서가 더 뒷자리일 때 true값을 반환합니다.
}

짜잔!
함수도 클로저니까 저런 형태로 적어주어도 되겠네요!
그럼 이번에는 인라인 클로저(?)의 형태로 나타내볼까요~~?

 

reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in
    return s1 > s2
})

reversedNames라는 변수의 값을 할당함과 동시에 위에서 만들었던 backward()메서드 자리에 코드블럭{}이 들어갔군요!
이렇게 함수로 따로 정의된 형태가 아닌 인자로 들어가 있는 형태의 클로저를 인라인 클로저라고 합니다.
앞의 갈호()안의 파라이터를 받아서 ->의 다음에 적혀있는 형태(지금은 Bool이 되겠죠?)값이 반환됩니다.
그 다음에는 in키워드를 적고, 클로저의 바디(body)를 적어 어떤 기능을 수행하는지 작성하면 됩니다👍🏻

 

reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in return s1 > s2 } )

클로저의 바디(body)가 짧으면(한줄이면) 이렇게 한줄로 축약시킬 수도 있어요!

 

reversedNames = names.sorted(by: { s1, s2 in return s1 > s2 } )

우리는 현재 String배열 names에서 sorted()라는 메서드를 호출해서 사용하고 있습니다.
그럼, s1, s2에 들어가는 값이 String이라는 것을 알겠죠??
이처럼 문맥에서 타입 추론(Inferring Type From Context)이 가능한 경우에는 더 생략한 형태로 적어줄 수 있어요!

 

reversedNames = names.sorted(by: { s1, s2 in s1 > s2 } )

세상에나🤭
클로저의 body가 한줄이어서, 단일표현 클로저로 만들어준 경우에는, 반환키워드(return)를 생략시킬 수 있습니다!

 

reversedNames = names.sorted(by: { $0 > $1 } )

??😳?
와우! 알수없는 기호가 등장했어요!

(생각하기싫은 bash와 PHP가 생각나는군요🤮)

Swift에서는 인라인 클로저에 자동으로 축약인자이름을 제공해요
이 인자는 값을 순서대로 $0, $1, $2 등으로 나타내는 거에요!
지금 우리는, 파라미터로 s1, s2를 사용하고, 반환 형태에도 똑같이 s1, s2가 들어가고 있어요
그래서 s1 -> $0, s2 -> $1로 매칭이 되어서
저렇게 파라미터와 in키워드를 생략한 형태로 적어줄 수 있는거에요!

 

reversedNames = names.sorted(by: >)

ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ
마지막 끝판왕입니다..
Swift의 String타입 연산자에는String끼리 비교할 수 있는 비교 연산자(>)가 있습니다!
그렇기때문에 그냥 이 연산자를 사용하면 보다 간결하게 나타낼 수 있어요!
(연산자 메서드가 궁금하면 클릭해보세요!)




이렇게, 클로저의 기본 개념과, 클로저 표현(Closure Expressions)에 대해 알아보았어요!
함수는 코드의 재사용이 많아질 수록 빛나는 친구지만,
진짜 딱 한번 쓰이는 간결한 친구라면 클로저의 형태가 더 좋지 않을까요?🤔
다음 글에서는 후위 클로저(Trailing Closures)에 대해 소개해보겠습니다!

 

이해가 안되는 부분이나, 틀린 부분이 있으면 코멘트를 남겨주세요!
피드백은 정말정말 환영입니다🎉🎉

 

Reference

공식문서
공식문서 번역본

728x90
반응형

'Swift' 카테고리의 다른 글

값 캡쳐 (Capturing Values)  (0) 2021.03.25
후위 클로저 (Trailing Closures)  (0) 2021.03.25
이름 짓기  (0) 2021.02.13
Initializer  (0) 2021.01.02
Inheritance  (0) 2021.01.02