Swift - 함수(Functions)

이재원·2024년 8월 1일
0

Swift

목록 보기
8/13
post-thumbnail

함수(Functions)

오늘은 기본중의 기본인 함수에 대해 정리를 해 보려고 합니다.

함수는 다른 언어에서도 기본이기 때문에, 특별히 기억할 만한 부분이나 다른 언어와 차이점을 중점으로 정리를 해 보겠습니다.

반환 타입이 있는 함수

반환값을 가진 함수는 리턴타입을 정의해 줘야 합니다.

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

sayHelloWorld() 뒤에 -> 으로 리턴 타입을 가리키고 있습니다.

이처럼 Swift에서는 함수의 리턴 타입을 -> 으로 명시해 주면 됩니다.

반환 타입이 없는 함수

반대로 반환값이 없는 함수는 -> 을 제거해 주면 됩니다.

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

여러개의 반환값이 있는 함수

여러개의 값을 반환하기 위해서는 튜플을 사용하면 됩니다.

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는 가장 작은 값과 가장 큰 값을 한꺼번에 반환합니다.

반환된 값에 접근할 때는 이름으로 접근할 수 있도록 라벨되어 있기 때문에 .을 이용하여 접근하면 됩니다.

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"

minMax(array: ) 함수는 옵셔널을 통해 빈 배열이 반환될 경우 안전하게 처리할 수 있습니다.

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

값에 접근할 때는 옵셔널 바인딩을 통해 접근하면 됩니다.

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"

암시적 반환

Swift에서 함수는 조금 특이한 반환이 있습니다.

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

해당 코드를 보면 잘못 작성된 것이 아닐까 하는 생각이 듭니다.

하지만 위 코드는 정상적인 코드이기 때문에 출력도 가능합니다.

print(greeting(for: "Dave"))
// Prints "Hello, Dave!"

이와 같은 형태의 코드가 작동하는 이유는 Swift에서 함수의 전체 본문이 한줄로 표현이 된다면 함수는 맹목적으로 표현식을 반환하기 때문입니다.

즉, retrun 키워드가 없더라도 반환 시킨다는 것입니다.

인수 라벨과 파라미터 이름

인수 라벨 지정

파라미터 이름 앞에 별칭을 지어줄 수 있습니다.

func greet(person: String, from hometown: String) -> String {
    return "Hello \(person)!  Glad you could visit from \(hometown)."
}
print(greet(person: "Bill", from: "Cupertino"))
// Prints "Hello Bill!  Glad you could visit from Cupertino."

인수 라벨을 사용하여 별칭을 지어주면 문장과 같은 표현방식으로 함수를 호출할 수 있는 동시에 읽기 쉽고 의도가 명확한 함수를 제공할 수 있습니다.

인수 라벨 생략

만약 함수 호출시 파라미터 이름을 사용하고 싶지 않다면 언더바(_)를 통해 인수 라벨을 생략할 수 있습니다.

func someFunction(_ firstParameterName: Int, secondParameterName: Int) {
    // In the function body, firstParameterName and secondParameterName
    // refer to the argument values for the first and second parameters.
}
someFunction(1, secondParameterName: 2)

가변 파라미터

가변 파라미터(variadic parameter)는 0개 이상의 특정 타입의 값을 허용하는 것으로, 함수 호출시 여러개의 입력값이 전달될 수 있는 특정 파라미터는 가변 파라미터를 사용합니다.

가변 파라미터는 파라미터의 타입 이름 뒤에 세개의 간격 문자 (. . .)를 추가하여 작성하면 됩니다.

func arithmeticMean(_ numbers: Double...) -> Double {
    var total: Double = 0
    for number in numbers {
        total += number
    }
    return total / Double(numbers.count)
}
arithmeticMean(1, 2, 3, 4, 5)
// returns 3.0, which is the arithmetic mean of these five numbers
arithmeticMean(3, 8.25, 18.75)
// returns 10.0, which is the arithmetic mean of these three numbers

In-Out 파라미터

함수의 파라미터는 기본적으로 상수입니다. 따라서 함수 내에서 파라미터 값을 변경하려고 하면 컴파일 에러가 발생합니다.

하지만 만약 inout 키워드를 사용한다면 파라미터의 값을 변경할 수 있게 됩니다.

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

inout 키워드가 사용된 함수는 변수만 전달할 수 있습니다.

함수 호출시에는 변수 앞에 & 를 붙여줍니다.

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

함수 타입

함수 타입 사용

Swift에서는 변수에 적절한 함수 타입을 할당할 수 있습니다.

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

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

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

mathFunction은 변수이기 때문에 타입이 일치하는 다른 함수로 할당 가능합니다.

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

물론 타입을 명시하지 않고 Swift에게 추론을 맡길 수도 있습니다.

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

파라미터 타입으로 함수 타입

함수의 파라미터로 함수를 사용할 수 있습니다.

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

이렇게 addTwoInts 함수를 printMathResult 함수의 파라미터로 전달하여 두 정수의 합울 출력할 수 있습니다.

반환 타입으로 함수 타입

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

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

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

var currentValue = 3
let moveNearerToZero = chooseStepFunction(backward: currentValue > 0)
// moveNearerToZero now refers to the stepBackward() function

chooseStepFunction(backward: )는 리턴 타입으로 (Int) -> Int 와 같은 형태를 갖고 있습니다.

이는 stepForwardstepBackward 함수의 매개변수 타입과 리턴 타입의 형태가 일치한 것을 확인할 수 있습니다.

즉, (Int) 는 함수의 매개변수 타입을 나타내는 것이고, -> Int 는 전달받은 함수의 리턴 타입과 일치함을 알 수 있습니다.

이러한 형태는 중접 함수에서도 동일합니다.

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!

함수 요약

  • 함수의 반환 타입은 -> 뒤에 명시한다.
  • 반환값이 없는 함수는 ->를 사용하지 않는다.
  • 튜플을 사용하여 여러 값을 반환 가능하다.
  • 옵셔널을 통해 함수의 리턴값을 안전하게 처리할 수 있다.
  • 함수의 전체 본문이 한 줄일 경우 return 키워드 없이도 값을 반환할 수 있다.
  • 파라미터 앞에 인수 라벨일 지정하여 별칭을 작성할 수 있다.
  • 언더바(_)를 사용해 인수 라벨을 생략할 수 있다.
  • 가변 파라미터는 특정 타입의 값을 여러 개 받을 수 있는 파라미터로, 타입 이름 뒤에 ...를 붙여 작성한다.
  • inout 키워드를 사용해 파라미터의 값을 함수 내부에서 변경할 수 있고, 함수 호출 시 변수 앞에 &를 붙인다.
  • 함수를 파라미터로 사용할 수 있다.
  • 함수의 반환 타입으로 함수를 사용할 수 있다.
  • 함수 내에 함수를 정의하여 중첩 사용할 수 있다.

마무리

오늘은 모든 프로그래밍 언어의 기본 중 하나인 함수에 대해 알아봤습니다.

C나 파이썬에서 사용하는 함수와 대부분 비슷하지만, Swift만의 고유한 구문들도 있었는데요. 처음에는 익숙하지 않아 어색한 부분도 있지만 익숙해지기만 한다면 굉장히 편리하게 코드를 작성할 수 있을 것 같습니다.

아직은 미숙하지만 조금씩 사용해 보면서 적응해 나가야 될 것 같아요🙂

출처
이 글을 Swift 공식 문서를 읽고 정리한 글입니다.
https://bbiguduk.gitbook.io/swift/language-guide-1/functions

profile
20학번 새내기^^(였음..)

0개의 댓글