함수는 대부분의 프로그래밍 언어에서 지원하는 개념으로, 프로그램의 실행 과정 중에서 독립적으로 처리될 수 있는 부분을 분리하여 구조화한 객체를 의미합니다. 이렇게 독립적으로 작성한 함수는 여러 번 호출하여 사용할 수 있어서 같은 코드를 반복하여 작성할 수 없습니다.

스위프트에서도 함수를 이용하여 한번 작성된 코드를 여러 곳에서 호출하여 사용할 수 있습니다. 특히 스위프트는 함수형 프로그래밍 패러다임을 채택하고 있는 언어이므로 함수형 프로그래밍의 특성을 이해하는 것은 매우 중요합니다.

1. 함수의 기본 개념

우리가 중고등학교 시절 배운 함수를 기억할 것입니다. f(x) = y 라는 함수가 있다면 x라는 입력값을 받아 내부 처리 과정을 거친 후 y라는 결과를 반환받습니다. 여기서 x를 인자값 혹은 파라미터라고 하며, y를 반환값 혹은 리턴값이라고 합니다. 프로그래밍에서의 함수도 이와 같습니다.

함수는 일반 함수와 사용자 정의 함수로 나뉩니다. 일반 함수는 프로그래밍 언어나 프레임워크 수준에서 제공하는 함수로 기본적인 데이터의 처리나 연산 등을 수행하기 위한 목적으로 사용됩니다. 대표적으로 출력을 위한 함수인 print() 가 있습니다. 우리는 print() 라는 함수를 만들지 않았지만 사용하기 때문입니다.

하지만 개발을 하다보면 이러한 일반 함수만으로는 충분하지 않습니다. 이때 우리는 필요한 함수를 직접 만들어야 하는데 이를 사용자 정의 함수라고 합니다.

함수를 사용하지 않고도 프로그래밍은 가능합니다. 함수 내부 코드만 사용하면 되기 때문입니다. 하지만 함수가 중요한 의미를 갖는 것은 다음과 같은 이점이 있기 때문입니다.

  1. 동일한 코드가 여러 곳에서 사용될 때 이를 함수화하면 재작성할 필요 없이 함수 호출만으로 처리할 수 있습니다
  2. 전체 프로세스를 하나의 소스 코드에서 연속적으로 작성하는 것보다 기능 단위로 함수화하면 가독성이 좋아지고, 코드와 로직을 이해하기 쉽습니다.
  3. 비즈니스 로직을 변경해야 할 때 함수 내부만 수정하면 되므로 유지보수가 용이합니다.

1-1. 사용자 정의 함수

사용자 정의 함수를 정의하는 방식은 다음과 같습니다

func 함수이름(매개변수1: 타입, 매개변수2: 타입: ....) -> 반환타입 {
    실행내용
    return 반환값
}

함수를 정의할 때 function의 약자인 func 키워드를 사용합니다. 그 다음 함수의 이름을 작성하는데, [+, , *, /] 같은 연산자와 예약어는 사용할 수 없습니다. 함수 이름에 사용할 수 있는 문자들은 영어, 숫자, 한자, 바이너리 이미지 등으로 다양하지만 첫 글자는 반드시 영어 또는 언더바(_)로 시작해야 합니다. 언더바 이외 특수문자나 숫자로 시작할 경우 컴파일러에 의해 오류가 발생합니다. 대신 두 번째 글자부터는 이런 제약이 없으므로 영어, 숫자, 일부 특수문자를 충분히 활용할 수 있습니다.

하지만 일반적으로 함수명을 지을 땐 숫자를 사용하지 말고 의미를 잘 전달할 수 있는 문자로만 만드는 것이 좋습니다.

다음으로는 함수의 인자값 개수와 형태를 정의하기 위해 소괄호 영역을 표시해 주는 것입니다. 입력값을 대입 받기 위한 변수의 이름과 타입이 정의되는데 이를 매개변수, 영어로는 파라미터라고 합니다. 매개변수가 여러개라면 ","를 통해 구분하며, 매개변수가 없는 경우 소괄호 내 아무것도 작성하지 않아도 됩니다.

함수의 반환 타입을 표시할 때는 "->" 기호와 함께 표시합니다. 이 기호 다음에 작성된 자료형이 함수가 반환하는 값의 타입입니다. 함수의 성격에 따라서는 반환값이 전혀 없는 함수를 작성할 수도 있습니다. 이 경우에는 "->"와 반환타입을 작성하지 않으면 됩니다.

함수 내부에서 실행내용이 모두 실행되고 결과값을 반환하는데 이때 사용하는 키워드가 return입니다. 다음 예제로 자세히 살펴보겠습니다

// 1. 매개변수와 반환값이 모두 없는 함수
func printHello() {
    print("안녕하세요")
}

// 2. 매개변수는 없지만 반환값은 있는 함수
func sayHello() -> String {
    let returnValue = "안녕하세요"
    return returnValue
}

// 3. 매개변수는 있으나 반환값이 없는 함수
func printHelloWithName(name: String) {
    print("\\(name)님, 안녕하세요")
}

// 4. 매개변수와 반환값이 모두 있는 함수
func sayHelloWithName(name: String) -> String {
    let returnValue = "\\(name)님, 안녕하세요"
    return returnValue
}

2번과 4번 예제에서 "->" 뒤의 반환타입과 return 뒤의 변수 타입은 일치해야 합니다.

반환값이 없는 함수의 경우에도 return 키워드를 종종 사용하는데, 이때의 return은 함수의 실행을 명시적으로 종료할 목적으로 사용됩니다. 아래 함수는 옵셔널 바인딩이 실패했을 경우 return을 호출하여 실행을 종료합니다

func hello(name: String?) {
    guard let _name = name else {
        return
    }
    
    print("\\(_name)님, 안녕하세요")
}

1-2. 함수의 호출

함수를 정의하는 방법을 알았으니 실행하는 방법을 배워보겠습니다. 함수를 실행하는 것을 함수를 호출한다고 표현하는데 기본적으로 함수의 이름에 괄호를 붙이면 됩니다.

printHello()
// "안녕하세요"

함수 호출시에는 func 키워드는 사용하지 않습니다. 그리고 뒤 ()은 선언시의 ()와는 다릅니다. 선언시의 괄호는 매개변수를 선언하기 위한 영역이라면, 호출시에 사용하는 괄호는 함수를 호출하는 연산자입니다.

매개변수가 없다면 빈 괄호만 붙여서 호출하면 되지만, 매개변수가 잇다면 괄호 안에 인자값을 넣어서 호출해야 합니다.