[Swift 프로그래밍] 함수 (Function)

이정훈·2022년 5월 11일
1

Swift 기본

목록 보기
4/22
post-thumbnail

본 내용은 스위프트 프로그래밍 3판 (야곰 지음) 교재를 공부한 내용을 바탕으로 작성 하였습니다.

스위프트의 특징 중 하나인 함수형 프로그래밍 언어는 함수를 일급 객체로 다룬다는 것이다. 이러한 일급 객체는 다음과 같은 특징을 가진다.

  • 함수를 전달 인자로서 사용이 가능하다.
  • 동적 프로퍼티 할당이 가능하다.
  • 변수나 데이터 구조 안에 저장이 가능하다.
  • 반환 값으로서 함수를 사용할 수 있다.

이러한 특징을 바탕으로 Swift의 함수에 대하여 알아 보자

함수의 정의


Swift에서 함수를 정의하는 방법은 다음과 같다.

func 함수이름(매개변수...) -> 반환값 {
	수행문
    return 반환값
}

조건문과 반복문에서 소괄호() 생략이 가능 했다면 함수에서 소괄호는 필수적이다.

또한 Swift에서는 내부 수행문이 한줄이고, 결과로 나온 값이 반환 값과 일치한다면 return 키워드 생략이 가능하다.

전달인자 레이블


매개변수와 함께 전달인자 레이블을 사용함으로서 함수 호출시 매개변수가 어떤 역할로 사용이 되는지 명확하게 해줄 수 있다.

func present(from myName: String, to yourName: String) -> String {
    return "\(myName)\(yourName)에게 선물 했습니다." //함수 내부에서는 매개변수
}

let presentToYou: String = present(from: "jeunghun", to: "Son") //함수 외부에서는 전달인자 레이블
print(presentToYou)

위의 예시에서 from과 to를 전달인자 레이블(Argument Label), myName과 yourName을 매개변수 이름(Parameter Name)이라고 한다.

전달인자 레이블을 사용한 경우 함수 내부에서는 매개변수 이름으로 인자 값을 사용할 수 있고, 함수 외부에서는 전달인자 레이블을 통해 함수를 호출한다.

위의 예시는 전달인자 레이블 from과 to를 사용하여 'jeunghun이 son에게' 라는 의미로 좀더 명확하게 표현하였다.

만약 전달인자 레이블을 사용하고 싶지 않다면, 와일드 카드 식별자_를 사용하여 구현이 가능하다.

func mulLoop1(_ num: Int, _ repeatCount: Int) -> Int {
    var result: Int = 1
    
    for _ in 1...repeatCount {
        result *= num
    }
    return result
}

print(mulLoop1(2, 3))

와일드 카드 식별자(_)를 사용하여, 2는 num 매개변수에 3은 repeatCount 매개변수에 각각 대응하여 전달하게 된다.

스위프트에서는 전달인자 레이블만 변경하여도 서로 다른 함수로 인식하여 함수를 중복 정의(overload) 할 수 있다.

매개변수 기본값


Swift에서는 매개변수에 기본 값을 입력해 줄 수 있다.

func mulLoop2(_ num: Int, _ repeatCount: Int = 2) -> Int {
    var result: Int = 1
    
    for _ in 1...repeatCount {
        result *= num
    }
    return result
}

print(mulLoop2(2))   //repeatCount의 기본값 반영
print(mulLoop2(3, 3))

위의 mulLoop2 함수는 매개변수 repeatCount를 가지고 매개변수의 기본값을 2로 설정하였다. 그러면 첫 번째 print문과 같이 repeatCount 매개변수를 입력해 주지 않아도 매개변수의 기본값으로 함수가 동작한다.
물론 두번째 print문과 같이 매개변수의 값을 다시 설정해 주는것도 가능하다.

가변 매개변수


매개변수로 몇개의 값이 전달될지 모를때 가변 매개변수를 사용 할 수 있다.
가변 매개변수는 0개 이상의 값을 전달 받을 수 있으며, 함수에 오직 하나만이 존재한다.

func wishList(_ myWishList: String...) -> [String] {
    var result: [String] = [String]()
    
    for i in myWishList {
        result.append(i)
    }
    return result
}

print(wishList("iphone", "ipad", "macbook"))

위와 같이 매개변수 뒤에 (...)을 입력하여 가변 매개변수를 사용한다.

입출력 매개변수


함수의 전달인자는 대체로 값을 복사해서 전달한다.
그러나 매개변수로 참조를 넘기기 위해서는 입출력 매개변수를 사용한다. 전달인자를 참조로 넘기면 값을 참조하여 원래 값을 변경한다.

입출력 매개변수는 매개변수 타입 앞에 inout이라는 키워드를 사용하여 매개변수로 참조를 전달 받는 것을 명시한다. 또한 매개변수로 전달될 전달인자가 참조임을 표시하기 위해 &(앰퍼샌드) 키워드를 사용하여 표현한다.

var numbers: [Int] = [1, 2, 3, 4, 5]

func changeNumber(_ arr: inout [Int]) {
    arr[3] = arr[0]
}

changeNumber(&numbers)  
// &를 사용하여 전달인자가 참조 값임을 알림
print(numbers)

반환값이 없는 함수


반환값이 없는 함수는 반환값 위치에 Void를 쓰거나 반환값을 생략하면된다.

func helloWorld() -> Void {
    //Void는 아에 생략도 가능
    print("Hello World!")
}

데이터 타입으로의 함수


글 처음에 설명한 일급 객체의 특징으로 Swift의 함수는 하나의 객체로서 데이터 타입으로 사용이 가능하다.

typealias Calculate = (Int, Int) -> Int

Calculate라는 함수 형태로 데이터 타입을 정의 하였다. Calculate는 Int형을 매개 변수로 받고 반환 값으로 Int형을 반환하는 함수형 데이터 타입이다.

typealias Calculate = (Int, Int) -> Int

func addFunc(_ a: Int, _ b: Int) -> Int {
    return a + b
}
var mathCal: Calculate = addFunc
print(mathCal(4, 5))

일급 객체의 특징으로 함수를 변수에 대입 할 수 있기 때문에 mathCal 변수에 addFunc 함수를 대입하였고 mathCal 변수의 데이터 타입은 Calculate형이 된다.

일급 객체의 또 다른 특징으로 함수를 전달인자로서 사용이 가능하다. 다음 코드는 함수를 전달 인자로 활용하는 코드이다.

typealias Calculate = (Int, Int) -> Int

func addFunc(_ a: Int, _ b: Int) -> Int {
    return a + b
}

func mulFunc(_ a: Int, _ b: Int) -> Int {
    return a * b
}

var mathCal: Calculate = addFunc
//함수를 데이터 타입으로 사용, 함수를 변수에 저장 가능
print(mathCal(4, 5))

func printResult(_ function: Calculate, _ a: Int, _ b: Int) {
    //함수를 매개변수로 사용 가능
    print("result: \(function(a, b))")
}

printResult(mulFunc, 3, 4)

func chooseFunction(_ addFunction: Bool) -> Calculate {
    addFunction ? addFunc : mulFunc
}

printResult(chooseFunction(false), 5, 6)

마지막의 printResult 함수는 chooseFunction 함수의 Bool 값에 따라 addFunc 함수와 mulFunc 함수 중 하나를 반환하고 function 매개변수의 전달 인자로 전달 받아서 함수를 작동한다.

중첩 함수


스위프트에서는 함수 안에 함수를 구현하는 중첩 함수를 만들 수 있다. 상위 함수 내부의 함수는 지역 함수로 상위 함수 내부에서만 사용이 가능하다. 하지만 상위 함수의 반환 값을 함수로 한다면 내부의 함수도 외부에서 사용이 가능하다.

아래의 코드는 상위 함수에서 더하기와 곱하기 계산을 수행하는 함수 중 하나를 선택하여 반환하는 중첩 함수를 구현한 코드이다.

typealias Calc = (Int, Int) -> Int      //타입 별칭 설정
func chooseCalc(_ chooseAdd: Bool) -> Calc {
    func add(_ a: Int, _ b: Int) -> Int {
        return a + b
    }
    
    func mul(_ a: Int, _ b: Int) -> Int{
        return a * b
    }
    
    return chooseAdd ? add : mul
}

let chooseAdd: Bool = true  //더하기 함수를 선택
let saveCalc: Calc = chooseCalc(chooseAdd)  //반환 받은 함수를 상수에 저장
print(saveCalc(3, 4))

상위 함수인 chooseCalc 함수에서 add 함수와 mul 함수 중 하나를 선택하여 함수를 반환하도록 하였고 반환한 함수는 saveCalc 상수에 저장되어 함수를 실행하도록 구현하였다.

반환 값을 무시하는 함수


스위프트는 함수의 반환 값이 사용되지 않았을 경우 경고를 보낸다. 하지만 때로는 반환 값을 무시하는 경우가 생길 수 있기에 @discardableResult 키워드를 사용하여 경고를 무시 할 수 있다.

@discardableResult func someFunction(_ something: String) -> String {
    print(something)
    return something
}

someFunction("Good night!")     //반환 값을 사용하지 않아도 오류 무시
profile
새롭게 알게된 것을 기록하는 공간

0개의 댓글