Function

DevMinion·2022년 7월 29일
1

Function에 대해서 예제와 함께 알아보쟈🙌

지금까지 Function(Method)을 "어 나 쓸줄 알아~~" 하고 딥하게 공부하지 않은 채 넘어가곤 했다. 단순히 플젝에도, 예제에도 나는 Function을 사용했기에 내가 모든 것을 완벽하게 안다고 생각하는 안일하고 멍청한 판단하에 공부를 하지 않았던 것이다.

원래는 Closure에 대해 포스팅을 작성하던 차였다. 그런데 왠걸 내가 Closure를 딥하게 몰라...ㅋㅋ 그래서 더 생각해보니 Function도 딥하게 몰라ㅋㅋㅋ 이런 상황에 무슨 Swift고 iOS개발이야 그죠?

그래서 나를 위해 준비했습니다, Function!

First Class Citizen

함수는 1급 객체이다. 뒤에 배울 Closure도 1급 객체이다. 1급 객체가 무엇인지 모른다면, First_Class_Citizen <- 이 포스팅을 보고 오는 것을 추천한다!

Function? Closure?

함수는 다음 포스팅에 쓸 Closure이다.

엥? 먼소리고?

Function은 Named Closure이다. 즉 함수도 클로져이지만 이름이 있는 클로져이다. 그럼 Closure는? Unnamed Closure인 것이다. 이는 뒤에서 조금 더 다루도록 하고. 이제 함수에 대해서 딥하게 알아보자.

Default Parameters

함수의 파라미터에 기본형을 지정해줄 수 있다. 코드가 말보다 이해하기 쉬울 것이다.

//MARK: Default Parameters
func me(name: String = "Minion", age: Int = 24) {
    print("My name is \(name). My age is \(age)!")
}
me()
me(name: "Jay", age: 20)

해당 코드를 실행하면,

위의 Minion은 우리가 파라미터를 따로 지정해주지 않아 Default값이 출력된 모습이며 아래는 우리가 지정해준 파라미터 값으로 출력된 모습이다.

Variadic Parameters

가변 파라미터이다. 가변 파라미터란, 하나의 파라미터로 여러 개의 Arguments를 받아 사용할 수 있다.

가변 파라미터의 특징으로는,

  • 가변 파라미터의 타입은 배열(Array)이다.
  • 두 이상의 가변 파라미터를 선언, 사용할 수 있다.
  • 가변 파라미터 뒤에 오는 파라미터는 _(under bar)로 Argument name을 생략할 수 없다.
  • 가변 파라미터는 Default Parametes를 가질 수 없다.

정도가 있다. 하나씩 코드와 함께 알아보자.

//MARK: Variadic Parameters 기본
func printSum(nums: Int...) {
    print("\(nums[0]+nums[1]+nums[2])")
}
printSum(nums: 1,2,3) // 6

//MARK: 두 개 이상의 가변 파라미터
func doubleVariadic(first: Int..., second: Int...) {
    print(first, second)
}
doubleVariadic(first: 1,2,3,4,5, second: 5,4,3,2,1) // [1, 2, 3, 4, 5] [5, 4, 3, 2, 1]

//MARK: 가변 파라미터 뒤의 파라미터 Argument Label 생략
func test(of first: Int..., _ initValue: Int) {  } // error: A parameter following a variadic parameter requires a label

func test2(first: Int... = 10) {  } // Variadic parameter cannot have a default value

In-Out Parameters

알다시피 함수에 전달하는 파라미터를 함수의 내부에서 변경할 수 없다.

func someFunction(name: String) {
    name = "Hi" // Error: Cannot assign to value: 'name' is a 'let' constant
}

이렇게 someFunction의 파라미터인 name을 함수의 내부에서 변경하려고 시도하면 XCode에게 혼구녕이 난다.

어림도 없다. 암!!

그 이유는 위의 예제 Error에도 나와있다 시피 파라미터로 넘겨받는 값은 Value Type이며 상수이다. 즉 변경할 수 없는 것이다. 하지만 이전 Class와 Struct 포스팅의 예제를 보면 Reference Type은 let으로 선언해도 주소를 참조하기에 변경할 수 있다는 것을 확인할 수 있다. 그렇다면???

두둥. In-Out Parameter등장.

In-Out Parameter란 입출력 파라미터로, Value Type의 값을 Reference Type처럼 참조로 전달할 수 있도록 해준다.

입출력 파라미터의 사용은 파라미터의 타입을 쓰기 전에 inout키워드를 먼저 작성해주면 끝이다. 먼저 코드를 보도록 하자.

//MARK: In-Out Parameters
func nameChanger(name: inout String) {
    name = "Minion"
    print("Hello, \(name)")
}
var name: String = "Jay"
nameChanger(name: &name)

이렇게 함수의 밖에서 "Jay"를 함수의 파라미터로 넘겨도 내부에서 값을 바꿔 사용할 수 있다. 여기서 특이한 것은 &키워드를 사용하여 참조로 전달하는 것을 볼 수 있는데 이것이 어딘가 익숙하다. C언어에서 주소를 할당하던 그 것과 같다!! 자 이렇게 해당 코드를 돌려보면,

이렇게 정상적으로 값이 Minion으로 바뀌어 출력된 것을 확인할 수 있다.

Value / Reference Type in Function

Value Type Parameter

위에서 Value Type과 Reference Type이 나온 김에 Function에서의 두 타입을 알아보자.

함수의 파라미터에 Value Type과 Reference Type 모두 전달할 수 있다.

함수(Function)정복하기 2/3 - 개발자 소들이<- 여기 소들이님의 적절한 예제가 있어 참고해 보았다. 밑의 코드는 valueType의 parameter의 값을 복사하여 함수에서 사용하는 것을 보여주기 매우 적절한 예이다. myName을 "Minion"으로 할당하고 valueFunc함수의 파라미터로 넣어준다. 이때 우리가 앞서 배운 Class와 Struct에서 보았듯 Reference Type은 주소값을 참조하지만 Value Type은 값을 복사하여 사용한다.
DispatchQueue로 해당 함수가 3초 뒤에 이름을 확인한다. 이 동작을 하기 전에 파라미터로 넘긴 이름을 Minion에서 Jay로 변경한다. 코드와 결과는 밑에서 확인하자.

//MARK: Value Type & Reference Type in Function
//MARK: - Value Type
func valueFunc(name: String) {
    DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
        print("Check #2 : \(name)")
    }
    //print("Hi Value Type: \(name)")
}
var myName: String = "Minion"
valueFunc(name: myName)
myName = "Jay"
print("Check #1 : \(myName)")

이렇게 분명 "Minion"이던 값을 "Jay"로 변경 하였지만 이미 파라미터로 들어간 값은 값이 복사되어 파라미터로 할당된다. 따라서 해당 함수가 돌기 전 값을 변경해도 이미 myName변수의 값이 복사되어 들어갔기에 변경된 값이 출력되지 않는다. 그럼 Reference Type에서도 확인 해보자.

Reference Type Parameter

//MARK: - Reference Type
class Person {
    var name: String = "Minion"
}

func referenceFunc(person: Person) {
    person.name = "Jay"
}

var minion = Person()
referenceFunc(person: minion)
print("Hi Reference Type: \(minion.name)")

이렇게 기본 값이 Minion인 클래스의 인스턴스 값을 변경하면 변경되어 출력되는 것을 확인할 수 있다.

이로서 함수에 Value Type과 Reference Type을 모두 사용할 수 있으며 어떤 방식으로 동작하는지 알아보았다.

Nested Function

말 그대로 중첩 함수이다. 함수 내부에 또 다른 함수를 갖는 것을 말한다. 직접 코드로 확인해보자.

//MARK: Nested Function
func calcul(firstNum: Int, funcName: String ,secondNum: Int) {
    
    var result: Int = 0
    
    func plus(f: Int, s: Int) -> Int {
        return f + s
    }
    
    if funcName == "+" {
        result = plus(f: firstNum, s: secondNum)
    }
    
    print(result)
}

calcul(firstNum: 10, funcName: "+", secondNum: 20)

이렇게 10과 20이 더해져 30이 출력되는 것을 확인할 수 있다.

Function Types

함수 타입을 간단한 코드와 함께 알고 넘어가자.

//MARK: Function Type
//Parameter X
func someFunction1() {} // () -> ()
//Parameter O
func someFunction2(name: String) {} // (String) -> ()
//Return X
func someFunction3() {} // () -> ()
//Return O
func someFunction4(name: String) -> String {} // (String) -> (String)
//In-Out
func someFunction5(name: inout String) {} // (inout String) -> ()

References(Thx🤙)

(Swift) 함수(Function) 정복하기 2/3 - 개발자 소들이
Functions - The swift programming language

profile
iOS를 개발하는 미니언

0개의 댓글