Siwft) Function

11 minute read

Function (함수)

Overview

함수는 특정 작업을 수행하는 독립적인 코드 뭉치입니다.

함수에 식별할 수 있도록 이름을 지정하고, 이 이름은 작업을 수행할 때 호출하여 사용합니다.

매개 변수는 함수 호출을 단순화하는 기본값을 제공할 수 있으며 함수가 실행을 완료한 후

전달된 변수를 수정하는 in-out 매개 변수로 전달될 수 있습니다.

Swift의 모든 함수는 타입이 있는데, 매개변수 타입과 반환 타입으로 구성되어있습니다.

Swift의 다른 타입과 마찬가지로 이 타입을 사용할 수 있으므로 다른 함수에 대한 매개 변수로

함수를 전달하고 함수에서 함수를 반환할 수 있습니다.

함수의 범위 내에서 유용한 함수를 캡슐화하기 위해 다른 함수에 쓸 수도 있습니다.


함수 정의 및 호출 (Defining and Calling Functions)

함수를 정의할 때에는 함수가 입력으로 사용하는 하나 이상의 명명된 입력 값을 파라미터으로 정의할 수 있다.

또한 선택적으로 함수가 완료되면 출력으로 전달되는 값 타입(또는 반환 타입)을 정의할 수도 있다.

모든 함수에는 함수 이름이 있으며, 함수가 수행하는 작업을 설명한다.

함수를 사용하려면 함수를 이름으로 호출하고 함수 파라미터의 타입과 일치하는 입력 값을 전달한다.

함수의 인자는 항상 함수의 파라미터 목록과 같은 순서로 제공되야 한다.

아래 코드는 매개 변수안 (person:)에 사용자의 이름을 입력받아서 입력된 사용자에 대한

인사말을 호출하는 코드이다. -> 을 통해서 문자열을 반환하고 있다.

func greet(person: String) -> String {
    let greeting = "Hello, " + person + "!"
    return greeting
}

함수는 func 키워드를 앞에 붙여 사용한다. ->는 반환 화살표이고, 함수의 반환 타입을 나타내면

반환할 타입의 이름이 표시된다.

함수는 어떤 정의를 하는지, 무엇을 받는지 그리고 완료되면 무엇을 반환하는지 설명한다.

이 함수의 정의는 코드의 다른 곳에서 명확하게 호출하기 쉽게한다.

print(greet(person: "Jamking"))
// Prints "Hello, Jamking!"
print(greet(person: "Yagom"))
// Prints "Hello, Yagom"

greet의 함수에 Strign 타입의 값을 입력하여 greet(person: “Jamking”)와 같이 문자열 값을

호출한다. 함수가 문자열 값을 반환하기 때문에 print()함수에 호출하여 해당 문자열을 print하고,

위에 표시된 반환 값을 볼 수 있다.

greet(person:) 함수를 보면 greeting이라고 하는 새로운 상수에 문자열을 정의하고

간단한 인사말 메세지로 값을 주었다. 그 다음 반환 값을 사용하여 이 인사말이 함수에서 다시 전달된다.

함수는 여러번 호출 할 수 있으며 인자값에 함수에서 반환하는 타입을 잘 명시하고 입력해주면 된다.

위의 함수를 더 짧게 작성하는 방법은 return 값에 메시지를 작상하면 된다.

func greetAgain(person: String) -> {
    return "Hello again, " + person + "!"
}
print(greetAgain(person: "Jamking"))
// Prints "Hello again, Jamking!

함수의 파라미터와 반환 값(Funcgion Parameters and Return Values)

Swift에서는 함수의 파라미터와 반환 값이 매우 유연하다.

이름이 없는 단일 매개변수를 사용하는 단순 유틸리티 함수부터 명시적인 매개 변수와

다른 매개 변수 옵션을 사용하는 복잡한 함수까지 정의할 수 있다.

매개 변수가 없는 함수(Functions With Multiple Parameters)

함수는 매개 변수를 입력하지 않아도 되며 아래 코드는 String 타입을 반환하고

항상 같은 String 타입으로 지정된 값을 리턴한다.

func sayHelloWorld() -> String {
    return "Hello, world"
}
print(sayHelloWorld()) // "Helo, world"

위와 같이 함수 정의에는 매개 변수를 사용하지 않더라도 함수의 이름 뒤에 괄호가 필요하다.

또한 함수를 호출할 때에 함수 이름 뒤에 빈 괄호를 같이 입력해야한다.

여러 매개 변수가 있는 함수

함수는 ()괄호 안에 여러 매개 변수를 가질 수 있으며 쉼표로 구분한다.

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

greet 함수를 호출하려면 (person:alreadyGreeted)안에 표시 된 String과 Bool 값에

쉼표로 구분하여 전달하고 호출한다. 위쪽에서 작성했던 두 코드를 조건에 맞게 호출하는 함수이다.


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

함수는 반환 타입을 정의하지 않아도 된다.

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

위 함수는 반환 값이 정의되지 않았음에도 여전히 값을 반환한다.

정의된 반환 유형이 없는 함수는 Void 타입의 특수 값을 반환한다. 빈 튜플을 의미하고 빈 괄호를 쓴다.

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

func printAndCount(string: String) -> Int {
    print(string)
    return string.count
}
func printWithoutCounting(string: String) {
    let _ = printAndCount(string: string)
}
printAndCount(string: "Hello, world") // 12
printWithoutCounting(string: "Hello, world") // "Hello, world"

위 함수를 보면 printAndCount(string:) 함수는 반환 값이 Int이고,

인자값에 입력된 문자열의 Count를 정수 12로 출력되었다.

하지만 printAndCount(string:)을 printWithoutCounting(stirng:) 함수에서

호출하고 출력하였지만 pirntAndCount 함수의 반환 값은 무시되고 String으로 출력되었다.

    반환 값은 무시할 수 있지만 값을 반환한다는 함수는 항상 이를 수행해야 한다.

    정의 된 반환 형식을 가진 함수는 값을 반환하지 않고 컨트롤이 함수의 하단에서 빠질 수 없으며,

    실행할 때 컴파일 타임 오류가 발생한다.

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

함수의 반환 타입을 튜플 타입으로 사용하여 여러 값을 하나의 다중 반환 값의 일부로 반환할 수 있다.

아래 코드는 하나의 매개 변수에서 [int] 배열에서 가장 작은 값과 가장 큰 값을 찾는다.

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)
}

위 함수는 두 개의 Int 값을 포함하는 튜플을 반환한다.

최소값과 최대값의 변수를 array의 첫번 째 값으로 지정한다.

그런 다음 함수는 array의 나머지 값에서 반복되며 가 값이 각각 작거나 큰지를 확인 후

마지막으로 전체 최소값과 최대값은 두 개의 Int로 튜플 형식으로 반환된다.

튜플의 맴버 값은 함수의 반환 타입의 일부로 지정되기 때문에 도트 ‘.’를 통해 검색할 수 있다.

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

튜플의 이름은 함수의 반환 값의 일부로 지정되어있기에 튜플의 맴버는 함수에서

반환되는 시점에서 이름을 지정할 필요가 없다.


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

함수에서 반환할 튜플 타입이 전체 튜플에 대해 ‘값이 없음’을 가질 수 있는 가능성이 있을 경우,

옵셔널 튜플 반환 타입을 사용하여 전체 튜플이 0일 수 있다는 것을 반영할 수 있다.

(Int, Int)와 같이 닫힌 괄호 뒤에 물음표를 붙여 사용할 수 있다.

(Int?, Int?)와 (Int, Int)?은 다르다.
옵셔널 튜플 타입을 사용하면 튜플 내의 각 개별 값뿐만 아니라 전체 튜플도 선택적으로
사용 가능하다.

빈 array를 안전하게 처리하려면 옵셔널 튜플 반환 타입을 사용하여 minMax(array:)함수를 쓰고,

array가 비어 있을 때 0 값을 반환할 수 있다.

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)")
}
// min is -6 and max is 109

암시적 반환이 있는 함수(Functions With an Implicit Return)

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

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

위 두 함수는 같은 기능을 실행하며 하나의 반환 선으로 쓰는 모든 함수는

반환을 생략할 수 있다.

암시적 반환 값으로 작성하는 코드는 일부 값을 반환해야 한다.

예를 들어 fatalError(“Oh no!”) 또는 print(13)을 사용할 수 없다.


함수의 인수 이름과 매개 변수 이름(Function Argument Labels and Parameter Names)

Argument - 함수를 호출할 때 사용한다.

Parameter - 함수를 구현할 때 사용한다.

모든 매개 변수에는 고유한 이름이 있어야 한다.

여러 매개 변수가 동일한 인수 이름을 가질 수 있지만 고유한 인수 이름은 코드의 가독성을 높여준다.

인수 레이블 지정

매개 변수의 이름 앞에 인수 이름을 작성하고 공백으로 구분한다.

func someFunction(argumentLabel parameterName: Int) {
    // 매개 변수 이름은 인수 값을 참조한다.
}
func greet(person: String, from nometown: String) -> {
    return "Hello \(person)! Glad you could visit from \(hometown)."
}
print(greet(person: "Jamking, from: "Cupertino"))

인수 이름을 사용하면 함수가 표현적이고 문장 같은 방식으로 호출될 수 있다.

인수 이름 제외(Omitting Argument Labels)

매개 변수에 대한 인수 이름을 표시하지 않으려면 _ 을 사용한다.

func comeFunction(_ firstParameterName: Int, secondParameterName: Int) {

}
someFunction(1, secondParameterName: 2)

매개 변수에 인수의 이름이 있는 경우 함수를 호출할 때 인수 이름을 지정해야 한다.

매개 변수 기본 값(Default Parameter Values)

매개 변수 타입 뒤에 매개 변수에 값을 할당하여 함수의 매개 변수에 대한

기본 값을 정의할 수 있다. 기본값을 정의한 경우 함수를 호출할 때 해당 매개 변수를 생략할 수 있다.

func someFunction(parameterWithoutDefault: Int, parameterWithDefault: Int = 12) {

}
someFunction(parameterWithoutDefault: 3, parameterWithDefault: 6)
// parameterWithDefault is 6
someFunction(parameterWithoutDefault: 4)
// parameterWithDefault is 12

매개 변수 중 하나만 값이 있는 경우 값이 없는 매개 변수를 앞에 놓아야한다.

값이 없는 매개 변수는 함수의 의미에서 더 중요하다.

매개 변수를 먼저 기록하면 기본 매개 변수가 생략되었는지 여부에 관계없이

동일한 함수가 호출되고 있음을 쉽게 인식할 수 있다.

가변 매개 변수(Variadic Parameters)

가변 매개 변수는 특정 타입에 0개 이상의 값을 사용할 수 있다.

가변 매개 변수를 사용하여 함수를 호출할 때 매개 변수를 다양한 수의 입력 값을

전달할 수 있도록 지정할 수 있다.

매개 변수의 타입 이름 뒤에 마침표(…)를 세개 입력하여 가변 매개 변수를 사용할 수 있다.

다음 예제는 숫자 목록 길이에 대한 평균을 계산한다.

func arithmeticMean(_ numbers: Double...) -> Double {
    var total: Double = 0
    for number in numbers {
        total += number
    }
    return totla / Double(numbers.count)
}
arithmeticMean(1, 2, 3, 4, 5) // 3.0
arithmeticMean(3, 8.25, 18.75) // 10.0

가변 매개변수 뒤에 오는 첫 번째 매개변수에는 인수 이름이 있어야 한다.

인수 이름을 지정하면 어떤 인수가 가변 매개변수로 전달되고, 어떤 인수가 가변 매개변수

뒤에 오는 매개변수로 전달되는지 명확해 진다. 함수는 여러 가변 매개변수를 가질 수 있다.

In - Out 매개변수

함수의 매개변수는 기본적으로 상수이다. 클로저 내부에서 매개변수의 값을

해당 함수의 본문 내에서 변경하려고 하면 컴파일 오류가 발생한다.

쉽게 말해서 매개변수의 값을 변경할 수 없다는 것을 의미한다.

함수가 매개변수의 값을 수정하고 함수 호출이 끝난 후에도 이러한 변경이 지속되길 원한다면

해당 매개변수를 대신 in-out 매개변수로 정의할 수 있다.

인아웃 파라미터는 함수에 전달 된 값을 가지며 함수에 의해 수정되고 원래 값을

대체하기 위해 함수에 의해 다시 변환된다.

인 아웃 파라미터는 매개변수 타입 앞에 키워드를 넣어서 사용하면 된다.

  1. 변수를 인아웃 파라미터의 인수로만 전달할 수 있다.
  2. 상수 및 리터럴은 수정할 수 없으며 상수, 리터럴 값을 인수로 전달할 수 없다.
  3. & 앰퍼샌드를 변수 이름 앞에 인수로 전달할 때 이름 바로 앞에 배치하여 함수에 의해 수정할 수있다.

인아웃 매개변수에는 기본값을 사용할 수 없고, 가변 매개변수는 인아웃으로 표시할 수 없다.

func swapTwoInts(_ a: inout Int, _ b: inout Int) {
    let temporaryA = a
    a = b
    b = temporaryA
}

위 함수는 단순히 b와 a를 스왑한다. 이 함수를 이용해서 타입이 Int인 두 값을 스왑할 수 있다.

&앰퍼센트를 통해 변수 앞에 접두사로 사용할 수 있다.

var someInt = 3
var anotherInt = 107
swapTwoInts(&someInt, &anotherInt)
print("someInt is now \(someInt), and anotherInt is now \(anotherInt)")
// someInt is now 107, and anotherInt is now 3

위 코드에 두 Int타입의 변수는 함수 외부에서 정의되었음에도 함수를 호출하여 수정된다.

인아웃 매개변수는 함수에서 값을 반환하는 것과는 다르다

ㅎ마수가 함수 본체의 범위를 벗어하는 효과를 가질 수 있는 대안적인 방법이다.


함수 타입

모든 함수는 파라미터 타입과 함수의 반환 타입으로 구성된 특정 함수 타입을 가지고 있다.

func addTwoInts(_ a: Int, _ b: Int) -> Int {
    return a + b
}
func multiplyTwoInts(_ a: Int, _ b: Int) -> Int {
    return a * b
}

위 두개의 함수 타입은 (Int, Int) -> Int 이다. 또는

“Int타입을 가진 두개의 매개변수가 있으며 타입 Int의 값을 반환하는 함수다.”

다음은 함수의 반환 값이 없는 코드다.

func printHelloWorld() {
    print("Hello, world")
}

위 함수는 반환값이 없으며 Void를 반환하는 함수이다.

함수 타입 사용

Swift의 다른 타입과 마찬가지로 함수 타입을 사용한다.

예를들어 상수 또는 변수를 함수 타입으로 정의하고 해당 변수에 적절한 함수를 할당할 수 있다.

var mathFunction: (Int, Int) -> Int = addTwoInts

해석하면 mathFunction변수는 ‘Int 값을 두개 가져가고 Int 값을 반환하는 함수’의 유형이다.

그리고 addTowInts라는 함수를 참조하도록 새 변수를 설정한다.

위 코드의 설정을 통해 mathFunction이라는 이름으로 할당된 함수를 호출할 수 있다.

print("Result: \(mathFunction(2, 3))") // "Result: 5"

동일한 매칭 타입을 가진 다른 함수를 동일한 변수에 할당할 수 있다.

mathFunction = multiplayTwoInts
print("Result: \(mathFunction(2, 3))") // "Result: 6"

다른 타입들과 마찮가지로 함수를 상수 또는 변수에 할당할 때

함수 타입을 추론하도록 Swift가 도와준다.

let anotherMathFunction = addTwoInts
// anotherMathFunction is inferred to be of type (Int, Int) -> Int

매개변수 타입으로서 함수 타입(Function Types as Parameter Types)

다른 함수의 매개변수 타입으로 (Int, Int) -> Int와 같은 함수 타입을 사용할 수 있다.

이 기능을 사용하려면 함수가 호출 될 때 함수 호출자가 제공할 수 있는 기능 구현의

일부 측면을 남겨 둘 수 있다.

위에 정의했던 함수들을 예로 들어 이렇게 함수를 구현할 수 있다.

func printMathResult(_ mathFunction: (Int, Int) -> Int, _a : Int, _ b: Int) {
    print("Result: \(mathFunction(a, b))")
}
printMathResult(addTwoInts, 3, 5)
// Result: 8

printMathResult 함수는 세개의 파라미터를 갖고있다.

(Int, Int) -> Int유형과 a와 b를 정하여 모두 Int 타입이 된다.

그리고 addTwoInts함수를 통해 두 가지 입력 값으로 사용된다.

반환 타입으로서 함수 타입(Function Types as Return Types)

함수 타입을 다른 함수의 반환 타입으로 사용할 수 있다.

반환되는 기능의 반환 화살표 -> 뒤에 전체 기능 타입을 작성하면 된다.

아래 두 함수는 (Int) -> Int 기능을 가진다.

func stepForward(_ input: Int) -> Int {
    return input + 1
}
func stepBackward(_ input: Int) -> Int {
    return input - 1
}

다음 함수의 반환 타입은 (Int) -> Int 이다.

chooseStepFunction(backward:)를 선택하면 부울 매개변수를 기반으로

stepBackward(:) 또는 stepForward(:) 함수가 반환된다.

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

아래 코드는 currentValue 변수를 0에 더 가깝게 이동시키기 위해 양수 또는 음수 단계가

필요한지를 결정한다. 3의 초기값을 가지고 currentValue > 0이 True로 반환되고,

chooseStepFunction에서 stepBackward함수를 반환한다.

반환된 함수에 대한 참조는 moveNearerToZero 상수에 저장된다.

var currentValue = 3
let moveNearerToZero = chooseStepFunction(backward: currentValue > 0)
// 상수 moveNearerToZero는 stepBackward() 함수를 참조한다.

이제 moveNearerToZero를 활용해서 0까지 셀 수있다.

print("Counting to zero:")

while currentValue != 0 {
    print("\(currentValue)... ")
    currentValue = moveNearerToZero(currentValue)
}
print("zero!")
// 3...
// 2...
// 1...
// zero!

중첩 함수(Nested Functions)

중첩 함수를 이용해서 함수의 본문 내부에 함수를 정의할 수 있다.

중첩 함수는 기본적으로 외부로부터 숨겨져 있지만, 여전히 해당 함수를 둘러싸고

호출하여 사용할 수 있다.

함수를 둘러싸고 있는 함수는 중첩된 함수 중 하나를 반환하여

중첩된 함수를 다른 범위에 사용할 수 있게 한다.

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
}
var currentValue = -4
let moveNearerToZero = chooseStepFunction(backward: currentValue > 0)
// moveNearerToZero now refers to the nested stepForward() function
while currentValue != 0 {
    print("\(currentValue)... ")
    currentValue = moveNearerToZero(currentValue)
}
print("zero!")
// -4...
// -3...
// -2...
// -1...
// zero!

위 내용은 공식문서를 번역한 것입니다. 틀린 내용이 있다면 이메일 또는 댓글로 달아주세요!

Comments