swift & iOS/swift

[swift] 중첩 함수 (nested functions)

whale3 2022. 1. 19. 18:58

https://docs.swift.org/swift-book/LanguageGuide/Functions.html#ID178

 

스위프트 공식문서의 Functions 챕터에도 나오지만 흔히 말하는 함수는 대부분 글로벌 함수일 것이다. 어디서나 호출할 수 있는 함수이다(global scope).

 

중첩 함수는 이름처럼 함수 안에 작성하는 함수를 말한다. 아래처럼 chooseStepFunction 함수(글로벌 함수) 안에 작성된 함수들이 모두 중첩 함수 nested function이다. chooseStepFunction 함수는 chooseStepFunction() 처럼 호출할 수 있지만 중첩 함수들은 chooseStepFunction 함수 안에서만 호출할 수 있다.

// 출처: https://docs.swift.org/swift-book/LanguageGuide/Functions.html#ID178

func chooseStepFunction(backward: Bool) -> (Int) -> Int {
    func stepForward(input: Int) -> Int { return input + 1 }
    func stepBackward(input: Int) -> Int { return input - 1 }
    return backward ? stepBackward : stepForward
}

대신 이 중첩 함수들을 리턴값으로 반환하여 사용할 수 있다. 

 

// 출처: https://docs.swift.org/swift-book/LanguageGuide/Functions.html#ID178

var currentValue = -4

let moveNearerToZero = chooseStepFunction(backward: currentValue > 0)
// moveNearerToZero now refers to the nested stepForward() function
// 중첩 함수 stepForward를 변수 moveNearerToZero에 할당하여 아래와 같이 사용할 수 있다.

while currentValue != 0 {
    print("\(currentValue)... ")
    currentValue = moveNearerToZero(currentValue) // moveNearerToZero 호출
}

print("zero!")

// -4...
// -3...
// -2...
// -1...
// zero!

이 뿐만 아니라 중첩 함수는 자신을 감싸고 있는 바깥 함수의 값들을 '캡쳐링' 할 수 있다. (...can capture values from their enclosing function - 출처: https://docs.swift.org/swift-book/LanguageGuide/Closures.html) 바깥 함수에서 선언한 constants, variables 외에 arguments도 캡쳐링 할 수 있다. 중첩 함수 내부에서 바깥 함수의 값을 읽거나 수정할 수 있다. 바깥 함수가 사라져도 가능하다. 그러므로 '캡쳐링' 이란 자기 자신의 바깥에 선언된 값들을 읽거나 수정할 수 있는데, 그 바깥 환경이 사라져도 역시 읽거나 수정이 가능하게 하는 성질(?)이라고 정리할 수 있을 것 같다.

 

그래서 이 '캡쳐링'을 테스트 해보기 위해 위의 예제를 약간 바꿔봤는데,

func chooseStepFunction(backward: Bool) -> () -> Void {
    var count = 0
    
    func stepForward() {
        count += 5
        print("count stepForward: \(count)")
    }
    func stepBackward() {
        count += 7
        print("count stepBackward: \(count)")
    }
    
    return backward ? stepBackward : stepForward
}

var currentValue = -4
let moveBackword = chooseStepFunction(backward: true)
let moveForword = chooseStepFunction(backward: false)

moveBackword() // 7

moveForword() // 5 

moveBackword() // 14
moveBackword() // 21

moveForword() // 10

 

 

chooseStepFunction이 중첩 함수를 리턴하고 사라진 후에도 count 변수를 계속 수정하는 것을 볼 수 있다. 

 

 

 

 

반응형