Swift - 함수 (2_특징, 중첩)

이한솔·2023년 8월 1일
0

Swift 문법 🍎

목록 보기
10/32

일급 객체로서의 함수의 특징

1. 변수나 상수에 함수 대입 가능

함수타입 : 변수에 함수를 대입하면 그 변수는 함수 타입이 된다.
(함수 타입은 함수의 형태를 축약한 형태로 사용한다.)

// 정수를 입력받는 함수
func foo(base: Int) -> String {
    return "결과값은 \(base + 1)입니다"
}

let fn1 = foo(base: 5)
// 결과값은 6입니다

let fn2 = foo // fn2 상수에 foo 함수가 할당됨
fn2(5) // 결과값은 6입니다


(인자 타입1, 인자 타입2, ...) -> 반환 타입

func boo(age: Int) -> String {
    return "\(age)"
}

// 위 함수 타입
(Int) -> String

// 상수에 할당
1. let fn: (Int) -> String = boo
2. let fn: (Int) -> String = boo(age:)


func boo(age: Int, name: String) -> (String, Int) {
    return (name, age)
}

// 위 함수 타입
(Int, String) -> (String, Int)


func boo() -> String {
    return "empty values"
}

// 위 함수 타입
() -> String


func boo(base: Int) {
    print("param = \(base)")
}

// 위 함수 타입
(Int) -> ()


// 반환값이 없을 때는 Void라고 표현 가능 (인자값은 안됨)
(Int) -> ()  =>  (Int) -> Void
() -> ()  =>  () -> Void 


2. 함수의 반환 타입으로 함수 사용 가능

func plus(a: Int, b: Int) -> Int {
    return a + b
}

func minus(a: Int, b: Int) -> Int {
    return a - b
}

func times(a: Int, b: Int) -> Int {
    return a * b
}

func divide(a: Int, b: Int) -> Int {
    guard b != 0 else {
        return 0
    }
    return a / b
}

func calc(_ operand: String) -> (Int, Int) -> Int {
    switch operand {
    case "+" :
        return plus
    case "-" :
        return minus
    case "*" :
        return times
    case "/" :
        return divide
    default :
        return plus
    }
}


let c = calc("+")
c(3,4) // plus(3,4) = 7

let c2 = calc("-")
c2(3,4) // minus(3,4) = -1

let c3 = calc("*")
c3(3,4) // times(3,4) = 12

let c4 = calc("/")
c4(3,4) // divide(3,4) = 0


3. 함수의 인자값으로 함수 사용 가능

func incr(param: Int) -> Int {
    return param + 1
}

func broker(base: Int, function: (Int) -> Int) -> Int {
    return function(base)
}

broker(base: 3, function: incr) // 4

function이라는 파라미터는 정수를 파라미터로 받아 정수를 리턴하는 함수다.
실질적인 연산은 인자로 받는 함수에 달려 있기 때문에 broker(base:function:) 함수의 정의 구문만으로는 어떤 연산이 실행될지 짐작하기 어렵다.
이런 식으로 중개 역할을 하는 함수를 브로커(Broker)라고 한다.




함수의 중첩

외부 함수 : 내부 함수를 포함하는 바깥쪽 함수
내부 함수 : 함수 내에 작성된 함수는 내부 함수, 일반적으로 외부 함수를 거치지않으면 접근불가능하다 (함수의 은닉성)

💡 내부 함수 생명 주기(Life Cycle)
외부 함수가 종료되면 내부 함수도 종료된다. (함수 내에 작성할 수 있는 내부 함수 수는 제한이 없다.)

// 외부 함수
func outer(base: Int) -> String {
    // 내부 함수
    func inner(inc: Int) -> String {
        return "\(inc)를 반환합니다"
    }
    let result = inner(inc: base + 1)
    return result
}

outer(base: 3)
// "4를 반환합니다"
// inner라는 함수는 outer라는 함수를 통해서만 접근 가능
// 내부 함수는 외부 함수가 실행되면서 내부 함수에 대한 참조가 발생하면 생성
// 외부 함수가 종료되면서 내부 함수에 대한 참조도 종료되면 내부 함수는 소멸


// 외부 함수
func outer(base: Int) -> (Int) -> String {
    // 내부 함수
    func inner(inc: Int) -> String {
        return "\(inc)를 반환합니다"
    }
    
    return inner
}

let fn1 = outer(base: 3) // outer()가 실행되고, 그 결과로 inner가 대입됨
let fn2 = fn1(30) // inner(inc: 30)과 동일
// 내부 함수 inner를 외부 함수의 실행 결과로 반환함으로써 외부에서 내부 함수에 접근할 수 있게됨
// inner 함수가 소멸하지 않고 fn1에 할당된 채로 생명을 유지하다가 (30)이라는 함수 호출 연산자 구문을 만나 실행됨
// 외부 함수에서 내부 함수를 반환하게 되면 외부 함수가 종료되더라도 내부 함수의 생명이 유지됨


// 내부 함수에 외부 함수의 지역 상수나 지역 변수가 참조된 경우
func basic(param: Int) -> (Int) -> Int {
    let value = param + 20
    
    func append(add: Int) -> Int {
        return value + add
    }
    
    return append
}

let result = basic(param: 10) // basic 함수가 실행되고 내부 함수인 append가 반환됨
result(10) // 출력값: 40 
// basic 함수는 실행이 끝나 종료, 반환된 내부 함수 append는 상수 result가 참조하고 있어 계속 남아있다가 실행됨
// 코드가 실행될 때 value 상수는 존재하지 않아 오류가 발생할 것 같지만 실행된다. 왜? append 함수가 클로저를 갖기 때문에


3개의 댓글

comment-user-thumbnail
2023년 8월 1일

좋은 정보 감사합니다!

답글 달기
comment-user-thumbnail
2023년 8월 1일

함수 클로저(closure) 찾아보시면 좋을것 같아요!

답글 달기
comment-user-thumbnail
2023년 8월 1일

함수에 대한 좋은글 감사합니다!

답글 달기