[TIL] 10.06

Junyoung_Hong·2023년 10월 6일
0

TIL_10월

목록 보기
4/20
post-thumbnail

1. Closure

클로저는 보통 익명 함수라고 생각하는 사람들이 많다. 그렇지만 func로 시작하는 함수들도 모두 클로저이다.

클로저는 Named Closure, Unnamed Closure 두 가지 종류가 있다. 보통 우리가 사용하는 함수는 Named Closure로, 그냥 함수라고 부른다.

func playGuitar() {
	print("멋있게 기타 치는 중")
}

그리고 이름을 붙이지 않고 사용하는 함수, Unnamed Closure를 보통 클로저라고 부른다.

let closure = { print("멋있게 기타 치는 중") }

1-1. 클로저 표현식

클로저는 다음과 같은 기본 구조를 가지고 있다.

{ (parameters) -> returnType in
    // 클로저 내용
}
  • parameters: 클로저가 받을 입력 매개변수를 정의한다.
  • returnType: 클로저가 반환할 값의 타입을 정의합니다. 만약 클로저가 값을 반환하지 않을 경우 Void 혹은 생략할 수 있다.
  • in: 클로저의 매개변수와 반환 타입을 정의한 부분과 실제 클로저 코드를 분리하는 키워드이다.
  • 클로저 내용: 클로저가 실행할 코드 블록을 작성한다.

Named Closure -> Unnamed Closure

함수를 클로저로 바꿔보자.

일반적인 함수는 다음과 같다.

func add (no1: Int, no2: Int) -> Int {
    return no1 + no2
}

func라는 키워드와 add라는 함수의 이름을 가지고 있고, (no1: Int, no2: Int) 라는 입력부분과 -> Int라는 출력 부분이 있다.

클로저로 변환하기 위헤서는 func키워드와 add라는 함수의 이름을 제거한다.

(no1: Int, no2: Int) -> Int {
    return no1 + no2
}

그 다음, 출력 부분 다음에 쓰인 { 를 맨 앞으로 보낸다.

{ (no1: Int, no2: Int) -> Int
    return no1 + no2
}

그리고 { 가 있던 자리에 in이라는 키워드를 넣어주자.

{ (number1: Int, number2: Int) -> Int in
    return no1 + no2
}

1-2. 계산기

간단한 계산기를 만들어보자.

import UIKit

func calculator (n1: Int, n2: Int, operation: (Int, Int) -> Int) -> Int {
    return operation(n1, n2)
}

func add (no1: Int, no2: Int) -> Int {
    return no1 + no2
}

calculator(n1: 2, n2: 3, operation: add)

기본적으로 우리가 자주 사용하는 형태의 코드이다. 이 코드를 클로저로 바꾸는 과정은 다음과 같다.

add 함수를 클로저로 변환

우선 add 함수를 클로저로 바꿔보자.

{ (no1: Int, no2: Int) -> Int in
    return no1 + no2
}

클로저를 입력 매개변수로 넣을 수 있다.

import UIKit

func calculator (n1: Int, n2: Int, operation: (Int, Int) -> Int) -> Int {
    return operation(n1, n2)
}

calculator(n1: 2, n2: 3, operation: { (no1: Int, no2: Int) -> Int in
    return no1 + no2
})

또한 Swift는 값을 기반으로 데이터 유형을 추론하는 기능이 있다. 이를 유형 추론이라고 한다.
현재 매개변수에 2와 3이 입력되고 있는데, 이를 토대로 매개변수의 데이터 유형이 무엇인지 알 수 있다.

import UIKit

func calculator (n1: Int, n2: Int, operation: (Int, Int) -> Int) -> Int {
    return operation(n1, n2)
}

calculator(n1: 2, n2: 3, operation: { (no1, no2) -> Int in
    return no1 + no2
})

입력 데이터 유형을 알 수 있다면, 출력의 데이터 유형도 추론을 할 수 있다. 따라서 -> Int 부분을 제거해도 컴파일러가 출력의 데이터 유형을 추론할 수 있다. 제거하면서 return키워드도 제거할 수 있다.

import UIKit

func calculator (n1: Int, n2: Int, operation: (Int, Int) -> Int) -> Int {
    return operation(n1, n2)
}

calculator(n1: 2, n2: 3, operation: { (no1, no2) in no1 + no2 })

클로저에서는 매개변수도 익명으로 사용할 수 있다. 지금까지는 매개변수 이름을 no1no2으로 지정했다. 그리고 나중에 해당 매개변수 이름을 참조하여 표현식을 수행하고 있다. 이 부분을 익명의 매개변수 이름을 사용할 수 있다. $ 기호로 이를 수행 할 수 있다.

import UIKit

func calculator (n1: Int, n2: Int, operation: (Int, Int) -> Int) -> Int {
    return operation(n1, n2)
}

calculator(n1: 2, n2: 3, operation: { $0 + $1 })

$0이 첫번째 매개변수, $1이 두번째 매개변수를 뜻한다.

충분히 단축이 되었다고 느끼지만, 한 번 더 줄일 수 있다. Swift에는 함수의 마지막 매개변수가 클로저 일 때, 적용되는 규칙이 있다. 마지막 매개변수 이름을 생략하고, 클로저만 적는 것인데, 이를 후행 폐쇄라고 한다.

import UIKit

func calculator (n1: Int, n2: Int, operation: (Int, Int) -> Int) -> Int {
    return operation(n1, n2)
}

calculator(n1: 2, n2: 3) { $0 + $1 }

그렇지만 이렇게 짧게 줄이게 되면 가독성이 너무 떨어진다. 따라서 적당히(?) 줄이는 것을 추천한다.

1-3. 정수 배열 정렬

let numbers = [5, 1, 3, 2, 4]
let sortedNumbers = numbers.sorted { (a, b) -> Bool in
    return a < b
}

이 클로저는 두 개의 정수를 받아서 작은 수가 먼저 오도록 비교하고 true 또는 false를 반환한다.

클로저는 간단한 경우에는 축약된 형태로 작성할 수도 있으며, Swift는 타입 추론을 통해 매개변수 타입과 반환 타입을 자동으로 추측할 수 있다.

let sortedNumbers = numbers.sorted { a, b in
    return a < b
}

더 간결하게 작성할 수 있다.

let sortedNumbers = numbers.sorted { $0 < $1 }

1-4. 배열에 +1 하기

많은 숫자로 구성된 배열이 있고, 각 숫자에 1씩 더하고 싶다. 우선 배열을 만들고, 1씩 더하는 함수를 만들자.

import UIKit

let array = [1, 2, 3, 4]

func addOne (n1: Int) -> Int {
	return n1 + 1
}

1씩 더하기 위해 반복문을 사용하기도 하지만 map 함수를 사용하면 좀 더 쉬워진다.

import UIKit

let array = [1, 2, 3, 4]

func addOne (n1: Int) -> Int {
	return n1 + 1
}

array.map(addOne)

이제 함수를 클로저로 바꾸고 map함수에 넣어주자.

import UIKit

let array = [1, 2, 3, 4]

array.map({ (n1: Int) -> Int in
	return n1 + 1
})

다음으로 하나씩 제거하자. 유형 추론을 사용해서 타입을 제거하자. 타입을 제거했으니, return도 제거 할 수 있다.

import UIKit

let array = [1, 2, 3, 4]

array.map({ (n1) -> Int in
	n1 + 1
})

마지막으로 후행 폐쇄를 적용시키면 다음과 같아진다.

import UIKit

let array = [1, 2, 3, 4]

array.map{$0 + 1}
profile
iOS 개발자를 향해 성장 중

0개의 댓글