함수 (Functions) - 함수 파라미터와 반환값 (Function Parameters and Return Values)

00yhsp·2024년 4월 7일

함수 파라미터와 반환값 (Function parameters and return values)은 Swift에서 매우 유연하다. 이름이 지정되지 않은 단일 파라미터가 있는 간단한 유틸리티 함수에서 파라미터 이름과 다른 파라미터 옵션이 있는 복잡한 함수에 이르기까지 모든 것을 정의할 수 있다.

파라미터 없는 함수 (Functions Without Parameters)

함수는 입력 파라미터 정의를 요구하지 않는다. 여기 호출될 때마다 항상 같은 String 메세지를 반환하는 입력 파라미터가 없는 함수가 있다.

func sayHelloWorld() -> String {
    return "hello, world"
}
print(sayHelloWorld())
// Prints "hello, world"

함수 정의는 어떠한 파라미터가 없더라도 함수의 이름 뒤에 소괄호가 필요하다. 함수 이름은 함수가 호출될 때 빈 소괄호가 뒤따른다.

여러개 파라미터가 있는 함수 (Functions With Multiple Parameters)

함수는 함수의 소괄호 내에 콤마로 구분하여 여러개의 입력 파라미터를 가질 수 있다.

이 함수는 사람의 이름과 이미 인사말을 가지는지에 대해 입력으로 받으며 입력된 사람에 따라 적절한 인사말을 반환한다.

func greet(person: String, alreadyGreeted: Bool) -> String {
    if alreadyGreeted {
        return greetAgain(person: person)
    } else {
        return greet(person: person)
    }
}
print(greet(person: "Tim", alreadyGreeted: true))
// Prints "Hello again, Tim!"

person 이라는 라벨을 가진 String 인수값과 alreadyGreeted 이라는 라벨을 가진 Bool 인수값을 소괄호 안에 콤마로 구분하여 greet(person:alreadyGreeted:) 함수로 전달하여 호출한다.
이전 섹션에서 본 greet(person:) 함수와는 다른 함수인 것을 명심해야 한다.
두 함수 모두 greet 으로 시작하는 이름을 가지지만 greet(person:alreadyGreeted:) 함수는 2개의 인수를 가지지만 greet(person:) 함수는 오직 하나의 인수를 가진다.

반환값 없는 함수 (Functions Without Return Values)

함수는 반환 타입 정의를 요구하지 않는다. 다음은 반환하지 않고 String 값을 출력하는 greet(person:) 함수 버전이다.

func greet(person: String) {
    print("Hello, \(person)!")
}
greet(person: "Dave")
// Prints "Hello, Dave!"

반환값이 필요하지 않기 때문에 함수의 정의는 반환 화살표 (->) 또는 반환 타입을 포함하지 않는다.

Note:
엄밀히 말하면 greet(person:) 함수는 반환값을 정의하지 않았지만 여전히 반환값이 있다. 반환 타입이 정의되지 않은 함수는 Void 타입의 특별한 값을 반환합니다. 이것은 () 로 쓰여진 빈 튜플이다.

함수의 반환값은 호출될 때 무시될 수 있다.

func printAndCount(string: String) -> Int {
    print(string)
    return string.count
}
func printWithoutCounting(string: String) {
    let _ = printAndCount(string: string)
}
printAndCount(string: "hello, world")
// prints "hello, world" and returns a value of 12
printWithoutCounting(string: "hello, world")
// prints "hello, world" but does not return a value

첫번째 함수 printAndCount(string:) 은 문자열을 출력하고 문자 갯수를 Int 로 반환한다. 두번째 함수 printWithoutCounting(string:) 은 첫번째 함수를 호출하지만 반환값을 무시한다. 두번째 함수가 호출될 때 첫번째 함수에 의해 메세지는 출력되지만 반환된 값은 사용하지 않는다.

Note:
반환값은 무시할 수 있지만 함수는 항상 값을 반환할 것이다. 정의된 반환 타입이 있는 함수는 반환되는 값 없이 함수의 바닥에서 밖으로 빠져 나오는것을 허락하지 않고 그렇게 하면 컴파일 시 에러가 발생한다.

여러개의 반환값이 있는 함수 (Functions with Multiple Return Values)

단일 혼합형 반환값의 부분으로 여러개의 값을 반환하기 위해 함수의 반환 타입으로 튜플 타입을 사용할 수 있다.

아래 예제는 Int 값의 배열에서 가장 작은값과 가장 큰값을 찾는 minMax(array:) 함수를 정의한다.

func minMax(array: [Int]) -> (min: Int, max: Int) {
    var currentMin = array[0]
    var currentMax = array[0]
    for value in array[1..<array.count] {
        if value < currentMin {
            currentMin = value
        } else if value > currentMax {
            currentMax = value
        }
    }
    return (currentMin, currentMax)
}

minMax(array:) 함수는 2개의 Int 값을 포함한 튜플을 반환한다. 이 값들은 함수의 반환 값을 조회할 때 이름으로 접근할 수 있도록 min 과 max 로 라벨되어 있다.

minMax(array:) 함수의 본문은 배열의 첫번째 정수의 값을 currentMin 과 currentMax 라 불리는 2개의 동작 변수에 값을 설정하는 것으로 시작한다. 그러면 함수는 배열의 나머지 값들을 반복하고 각 값이 currentMin 과 currentMax 의 값보다 더 작거나 더 큰지 확인한다. 마지막으로 가장 작고 가장 큰 값은 2개의 Int 값인 튜플로 반환된다.

튜플의 멤버 값은 함수의 반환 타입이므로 가장 작은 값과 가장 큰 값을 찾기 위해 점 구문으로 접근할 수 있다.

let bounds = minMax(array: [8, -6, 2, 109, 3, 71])
print("min is \(bounds.min) and max is \(bounds.max)")
// Prints "min is -6 and max is 109"

튜플의 멤버 이름은 함수의 반환 타입의 일부로 이미 지정되어 있으므로 함수에서 튜플이 반환되는 시점에 이름을 지정할 필요가 없다.

옵셔널 튜플 반환 타입 (Optional Tuple Return Types)

함수에서 반환되는 튜플 타입이 전체 튜플에 대해 "값이 없을" 가능성이 있는 경우 옵셔널 튜플 반환 타입을 사용하여 전체 튜플이 nil 일 수 있다는 사실을 반영할 수 있다. (Int, Int)? 또는 (String, Int, Bool)? 와 같이 튜플 타입의 닫는 소괄호 다음에 물음표를 붙여 옵셔널 튜플 반환 타입을 작성한다.

Note:
(Int, Int)? 와 같은 옵셔널 튜플 타입은 (Int?, Int?) 와 같이 옵셔널 타입을 가지는 튜플과는 다르다. 옵셔널 튜플 타입은 튜플 안에 각각의 값이 옵셔널이 아니라 전체 튜플이 옵셔널이라는 의미이다.

위에서 minMax(array:) 함수는 2개의 Int 값을 포함하는 튜플을 반환한다. 그러나 이 함수는 배열이 전달될 때 아무런 안정성 확인을 하지 않는다. array 인수가 빈 배열을 포함하면 위에서 정의된 minMax(array:) 함수는 array[0] 을 접근할 때 런타임 에러가 발생한다.

빈 배열을 안전하게 처리하기 위해선 minMax(array:) 함수는 옵셔널 튜플 반환 타입을 가지고 배열이 비어있을 때 nil 을 반환한다.

func minMax(array: [Int]) -> (min: Int, max: Int)? {
    if array.isEmpty { return nil }
    var currentMin = array[0]
    var currentMax = array[0]
    for value in array[1..<array.count] {
        if value < currentMin {
            currentMin = value
        } else if value > currentMax {
            currentMax = value
        }
    }
    return (currentMin, currentMax)
}

옵셔널 바인딩을 통해 이 버전의 minMax(array:) 함수가 실제 튜플 값을 반환하는지 nil 을 반환하는지 확인할 수 있다.

if let bounds = minMax(array: [8, -6, 2, 109, 3, 71]) {
    print("min is \(bounds.min) and max is \(bounds.max)")
}
// Prints "min is -6 and max is 109"

암시적 반환을 가진 함수 (Functions With an Implicit Return)

함수의 전체 본문이 한줄로 표현이 된다면 함수는 맹목적으로 표현식을 반환한다.
예를 들어 아래의 두 함수는 모두 같은 동작을 한다.

func greeting(for person: String) -> String {
    "Hello, " + person + "!"
}
print(greeting(for: "Dave"))
// Prints "Hello, Dave!"

func anotherGreeting(for person: String) -> String {
    return "Hello, " + person + "!"
}
print(anotherGreeting(for: "Dave"))
// Prints "Hello, Dave!"

greeting(for:) 함수의 전체 정의는 인사말 메세지를 반환하고 이것은 짧은 표현으로 사용할 수 있다는 의미이다. anotherGreeing(for:) 함수는 긴 함수와 같이 return 키워드를 사용하여 같은 인사말 메세지를 반환한다. 단일 return 으로 작성된 함수는 return을 생략할 수 있다.

짧은 Getter 선언 (Shorthand Getter Declaration) 에서 살펴보겠지만 프로퍼티 getter 또한 암시적 반환을 사용할 수 있다.

Note:
암시적 반환값으로 작성하는 코드는 일부값을 반환하기 위해 필요하다. 예를 들어 암시적 반환값으로 print(13) 을 사용할 수 없다. 그러나 fatalError("Oh no!") 와 같이 Swift 가 암시적 반환이 일어나지 않는 것을 아는 경우에는 사용할 수 있다.

profile
iOS Dev

0개의 댓글