A Swift Tour로 Swift 공부하기 #4. Functions and Closure

minin·2021년 2월 12일
1

A Swift Tour

목록 보기
3/8

🍫 notion으로 보기
*본 포스트는 애플의 'A Swift Tour'를 바탕으로 작성되었으며, 공부하며 기록용으로 작성한 포스트이기 때문에 정확하지 않은 정보가 있을 수 있습니다!
** notion으로 작성한 문서를 임시로 올려둔 포스트이기 때문에 사진 링크의 오류와 문서의 형식 등으로 인해 보시기에 불편함이 있을 수 있습니다. (사진이 안나오거나 코드를 보기 불편한 점 등은 빠른 시일 내에 수정하도록 하겠습니다!)

4. Functions and Closure

func

**func funcName(_ paraName: paraType) -> returnType {**

code

}

func greet(person: String, day: String) -> String {
    return "Hello \(person), today is \(day)."
}
greet(person: "Bob", day: "Tuesday")

자연스럽게, 함수들은 그들의 매개변수parameter 이름을 그들의 arguments의 라벨로 사용한다.

custom argument label을 매개변수parameter 이름 **앞에** 적고, argument 라벨을 사용하지 않을 경우엔 _ 을 적는다.

  • 프로그래밍 내에서의 arguments

func greet(_ person: String, on day: String) -> String {
    return "Hello \(person), today is \(day)."
}
greet("John", on: "Wednesday")
: a custom argument label

tuple

**tuple**을 이용해서 compound value를 만들 수 있다. ex) 함수로부터 여러 값을 반환

tuple의 요소들은 이름 혹은 숫자로부터 참조될 수 있다.

*tuple : 순서가 없는 값의 세트an ordered set of value

func calculateStatistics(scores: [Int]) -> (min: Int, max: Int, sum: Int) {
    var min = scores[0]  //  score 배열의 첫 번째 원소로 초기화
    var max = scores[0]  //  score 배열의 첫 번째 원소로 초기화
    var sum = 0

    for score in scores {  //  scores 배열 안에 있는 요소 score만큼 반복
        if score > max {
            max = score
        } else if score < min {
            min = score
        }
        sum += score
    }

    return (min, max, sum)
}
let statistics = calculateStatistics(scores: [5, 3, 100, 3, 9])
//max = 100, min = 3, sum =120 => statistics = (100, 3, 120)
print(statistics.sum)
// Prints "120"
print(statistics.2) // statistics의 인덱스 (0, 1, 2)
// Prints "120"

Nested functions

functions can be nested. func은 함수 안에 또 다른 함수가 중첩하여 존재할 수 있다.

func returnFifteen() -> Int {
    var y = 10
    func add() {
        y += 5
    }
    add()  //  y += 5, y=15
    return y
}
returnFifteen()

func → func

func은 first-class 타입이다. 즉 func은 다른 func을 반환할 수 있다.

// makeIncrementer의 리턴 값: Int를 para로, Int를 반환하는 func
func makeIncrementer() -> ((Int) -> Int) {
// addOned의 리턴 값: Int    
	func addOne(number: Int) -> Int {  // number + 1해주는 함수
        return 1 + number
    }
    return addOne
}
var increment = makeIncrementer()  //  함수 초기화
increment(7)  //  실행 7+1

**func makeIncrementer() -> ((Int) -> Int)** // Int를 para로, Int를 반환하는 func

func addOne(number: Int) -> **Int** // Int를 반환하는 func

*함수의 정의 자체로 어떤 수행이 이루어지는 것은 아니다.

func funcName(func) → returnType

힘수는 매개변수로 다른 함수를 가져올 수 있다.

//  condition: (Int) -> Bool : func
func hasAnyMatches(list: [Int], condition: (Int) -> Bool) -> Bool {
    for item in list {
        if condition(item) {
            return true  //  *return을 만나면 함수를 빠져나간다
        }
    }
    return false
}

//  Bool을 리턴하기 때문에 ture/false 리턴
//  10보다 작으면 true, 그렇지 않으면 false
func lessThanTen(number: Int) -> Bool {
    return number < 10
}
var numbers = [20, 19, 7, 12]
//  numbers 정수 배열과, lessThanTen이라는 함수를 매개변수로 가져온다.
hasAnyMatches(list: numbers, condition: lessThanTen)

**func hasAnyMatches(list: [Int], condition: (Int) -> Bool) -> Bool {**

**code**

**}**

위의 함수 hasAnyMatches의 매개변수는 다음과 같다.

  • **list: [Int]:** 정수Int로 이루어진 배열 list
  • **condition: (Int) -> Bool: Int를 입력받아 Bool 값을 리턴하는 함수 condition**

그리고 for item in lis를 통해 list의 item들은 if condition(item)을 수행한다.

if문의 값은 bool(true/false)이기 때문에, condition(item)이 true일 경우에만 return true를 만나 함수 hasAnyMatches를 빠져나가게 된다.

주어진 매개변수 var numbers = [20, 19, 7, 12]의 경우,

20, 19는 if문을 통과하지 못해 return을 만나지 못하고,

7에서 if문을 통과해 return true를 만나 함수 hasAnyMatches를 빠져나온다.

*7 다음 원소인 12는 수행하지 않는다.

따라서 hasAnyMatches(list: numbers, condition: lessThanTen) = true 이다.

Closures (코드 블럭)

함수는 작성된 코드 블럭이 나중에 호출될 수 있다는 점에서클로저closures의 특별한 케이스이다. (함수는 이름이 있는 클로저)클로저 안에 있는 코드는 클로저가 생성됐을 때의의 범위scope에 있는 변수나 함수와 같은 것에 접근할 수 있는데, 이는 클로저가 실행될 때 다른 범위에 있더라도 가능하다. 우리는 이미 중첩함수nested functions를 통해 그 예시를 보았다. 중괄호{}로 코드를 묶어 이름없이 클로저를 작성할 수 있다. **in을 사용하여 인자와 코드(로직)를 분리한다.**


numbers.map({ (number: Int) -> Int in
    let result = 3 * number
    return result
})

***Closure**

{ (인자들) -> 반환타입 in
  code
}

***map: 배열을 변형하는 것. 리턴 값은 같은 사이즈의, 변형된 원소들을 포함한 배열이다.**

고차함수(매개변수로 함수를 받는 함수) : map, fileer, reduce

고차함수를 사용할 수 있는 타입

  • Sequence와 Collection 프로토콜을 따르는 타입: Array, dic, set
  • Optional

**Map: 변형. 데이터를 변형하고자 할 때 사용. 기존의 컨테이너의 값들은 변경되지 않고, 새로운 컨테이너를 생성하여 반환한다. map의 사용법은 for-in 구문과 큰 차이가 없다.** 다만, 맵을 사용하면 얻을 수 있는 이점

  1. 코드 재사용 용이
  2. 컴파일러 최적화 측면에서 성능 좋음
  3. 다중 스레드 환경에서, 하나의 컨테이너에 여러 스레드들이 동시에 변경 하려고 할 때 예측하지 못한 결과 발생을 방지할 수 있다.

experiment

홀수일 경우 0을 반환하는 클로저로 수정하기

numbers.map({ (number: Int) -> Int in
    let result = 3 * number
    return result % 2 != 0 ? 0 : result
})

Closures: 매개변수, 리턴 타입의 생략

너는 클로저를 더 간결하게 작성할 수 있는 몇 가지의 옵션이 있다. 클로저의 타입이 이미 명확할 때, 예를 들어 위임에 대한 답을 할 때, 매개변수의 타입, 그것의 리턴 타입, 혹은 모두를 생략할 수 있다. single statement 클로저는 함축적으로 그들의 statement의 값을 리턴한다.

let mappedNumbers = numbers.map({number in 3 * number})
print(mappedNumbers)

위의 코드에서 number의 타입과, 리턴 타입을 생략했다.

// prints "[20, 19, 12, 7]"

// var numbers = [20, 19, 7, 12] 각 원소 *3 한 값 리턴

refer to parameters by number instead of by name

매개변수의 이름 대신에 숫자로 참조할 수 있다. 이 접근 특히 짧은 closures에서 유용하다. 함수를 지나가는 가는 마지막 인자일 때 클로저는 괄호 뒤에 즉각 나타날 수 있다. 클로저가 함수의 하나뿐인 인자일 때 전체 괄호**()**는 생략해도 된다.

//  Closure can omit the parentheses
let sortedNumbers = numbers.sorted { $0 > $1 }
print(sortedNumbers)

//위의 것은 이것을 줄인 것
let sortedNumbers = numbers.sort { (firstObject, secondObject) in
    return firstObject > secondObject
}

***$0**, $1: swift에서 첫번째 객체, 두 번째 객체, ... 를 나타낼 때 줄여쓰는 표현

profile
🍫 iOS 🍫 Swift

0개의 댓글