Axe's Life

Swift - Closure ) 클로저 문법 본문

Swift Book

Swift - Closure ) 클로저 문법

devAxe 2020. 1. 16. 23:01

클로저는 세 가지 형태가 존재합니다.

 

  1. 이름이 있으면서 어떤 값도 획득하지 않는 전역 함수의 형태 (Global Function)

  2. 이름이 있으면서 다른 함수 내부의 값을 획득할 수 있는 중첩된 함수의 형태 (Nested Function)

  3. 이름이 없고 주변 문맥에 따라 값을 획득할 수 있는 축약 문법으로 작성한 형태 (Closure Expression)

 

함수와 메서드는 클로저의 일종입니다.

 

  • 함수(Function) == 글로벌 스코프 (전역)

  • 메서드(Method) == 형식 내부(클래스, 구조체, 열겨형)에서 선언

  • 클로저(Closure) == 이름이 없는 함수

즉, 함수와 메서드는 이름을 가진 클로저라고 볼 수 있습니다. (Named Closure)

 

그럼, 클로저의 표현 방법을 알아보겠습니다.

 


 

1. 기본 클로저

Tip: 클로저에 여러 줄의 표현(실행코드)이 들어가게 된다면 후행 클로저를 사용하는 것이 좋습니다.

 

기본 클로저의 모습을 보기 전, sorted(by:) 메서드에 인자로 함수를 전달하는 예시를 보겠습니다.

// sorted(by: (String, String) -> Bool))
// sorted(by:) == 2개의 String형 매개변수를 가지며 Bool형을 반환하는 함수를 받음

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

func backwards(s1: String, s2: String) -> Bool {
    return s1 > s2
}

let reversed = names.sorted(by: backwards) // ["Ewa", "Daniella", "Chris", "Barry", "Alex"]

함수 backwards(s1:s2:)를 만들어 sorted메서드의 인자로 전달해주었습니다.

 

이제 기본 클로저의 모습을 보겠습니다.

// backwards(s1:s2:)함수를 클로저 표현으로 대체
let reversed = names.sorted(by: { (s1: String, s2: String) -> Bool in
    return s1 > s2
})
print(reversed) // ["Ewa", "Daniella", "Chris", "Barry", "Alex"]

'func'키워드와 함수의 이름(backwards)을 없애고 나머지 코드를 sorted(by:) 메서드의 인자로 넣었다고 생각하면 됩니다.

 

하지만 클로저는 표현식(실행코드)을 작성하기 위해 들여 쓸 때는 'in'키워드를 사용합니다.

(Bool 오른쪽에 'in'이 추가된 거 보이시죠?)

 

클로저는 함수처럼 모듈화를 할 필요가 없을 때 매우 유용하고 간편합니다.

 

최종적으로 기본 클로저의 모습을 정리하자면 아래와 같습니다.

...{ (매개변수목록) -> 반환형 in
	실행코드
}

 


 

2. 후행 클로저 (Trailing Closure)

Tip: 클로저에 여러 줄의 표현(실행코드)이 들어가게 된다면 사용하는 것이 좋습니다.

(후행 클로저 사용 시 가독성이 좋습니다)

 

※주의: 마지막 전달 인자로 전달되는 클로저에만 해당 (맨 마지막 클로저만 후행 클로저 사용 가능)

 

먼저 후행 클로저의 모습을 보겠습니다.

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

후행 클로저는 클로저의 실행코드가 여러 줄이 될 경우 가독성을 높이기 위해 주로 사용합니다.

기본 클로저가 sorted(by:) 메서드 안에 코드를 넣은 반면, 후행 클로저는 코드를 메서드의 바로 뒤에 추가합니다.

 

참고로 후행 클로저는 메서드가 단 하나의 클로저만을 전달 인자로 하는 경우, 메서드의 소괄호가 생략 가능합니다.

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

 


 

3. 클로저 간소화

스위프트의 특징(Safe, Fast, Expressive) 중에서 Expressive(표현성)를 간소화를 통해 확실히 느낄 수 있습니다.

 

1. 문맥을 이용한 타입 유추

 

클로저에는 이러한 규칙이 있습니다.

 

클로저는 메서드에서 요구하는 형태로 전달해야 합니다.
(매개변수 타입이나 개수, 반환 타입이 같아야 전달 인자로서 전달 가능)

이러한 규칙 덕분에 스위프트는 문맥을 이용하여 타입을 유추할 수 있어, 매개변수 타입과 반환 타입을 생략할 수 있습니다.

 

클로저는 이미 메서드에 적합한 타입을 준수하고 있기에 문맥에 따라 적절히 타입을 유추 가능하다는 것입니다.

 

한마디로, 타입 생략이 가능하다는 것입니다!

 

매개변수 타입(String)과 반환 타입(Bool)이 생략된 모습

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

 

 

2. 단축 인자 이름

 

스위프트는 매개변수의 이름도 생략시킵니다.

매개변수의 이름을 명시하지 않고도 '$'와 숫자의 조합으로 단축 인자 이름이 사용 가능합니다.

let reversed = names.sorted(by: {
    return $0 > $1
})

매개변수의 이름을 명시하지 않아도 되기에 'in'키워드마저도 생략 가능합니다.

 

 

3. 암시적 반환 표현

 

"설마 생략할게 더 있겠어?"라고 생각하실 수 있겠지만...

네, 그렇습니다... 생략할게 더 있습니다!

 

클로저가 반환 값을 갖고, 내부의 실행문이 한 줄이라면, 암시적으로 해당 실행문을 반환 값으로 사용 가능합니다.

즉, 'return'키워드가 생략 가능합니다.

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

 

 

4. 연산자 함수

 

추가로 하나 더 있습니다...

 

클로저는 매개변수의 타입과 반환 타입이 연산자를 구현한 함수의 모양과 동일하다면, 연산자만 표기하더라도 알아서 연산하고 반환하여 줍니다.

 

연산자는 일종의 함수라는 것 아시나요?

연산자의 정의를 보시면

public func ><T : Comparable>(lhs: T, rhs: T) -> Bool

연산자의 함수를 클로저의 역할로 사용한 것입니다.

 

끝으로 이러한 코드가 됩니다.

let reversed = names.sorted(by: >)

 


 

부족한 설명 봐주셔서 감사합니다!

여러모로 부족한 부분이 많기에 혹시라도 잘못된 정보가 있다면 댓글로 알려주시면 감사하겠습니다!

 

<Axe's GitHub - Swift Book> Closure

Swift Book - Closure  <- 정리된 자료를 보고 싶다면, 클릭!

 

devMinseok/Swift_Book

Swift문법이 정리된 저장소입니다. Contribute to devMinseok/Swift_Book development by creating an account on GitHub.

github.com

 

'Swift Book' 카테고리의 다른 글

Swift - Array ) 배열의 기초  (0) 2020.01.20
Let's Swift Book!  (2) 2020.01.16
Comments