Swift/Swift 기본문법

Swift 기본 문법 - 9. 함수

728x90

함수

구조체, 클래스, 열거형 등 특정 타입에 연관되어 사용하는 함수를 메서드.

모듈 전체에서 전역적으로 사용할 수 있는 함수를 그냥 함수라고 합니다.

swift의 함수는 재정의(오버라이드)와 중복 정의(오버 로드)를 모두 지원합니다.

따라서 매개변수의 타입, 갯수에 따라 같은 이름의 함수를 여러 개 만들 수 있습니다.

func hello(name: String) -> String {
    return "Hello \(name)!"
}

let helloJenny: String = hello(name: "Jenny")
print(helloJenny)

func introduce(name: String) -> String {
    "제 이름은 " + name + "입니다."
}

let introduceJenny: String = introduce(name: "Jenny")
print(introduceJenny)

매개변수 이름과 전달인자 레이블

swift에서는 전달인자 레이블과 매개변수 이름을 따로 지정을 할 수 있습니다.

코드를 보면 어떻게 사용되는지 알 수 있습니다.

func 함수이름(전달인자 레이블 매개변수 이름: 매개변수 타입, 전달인자 레이블 매개변수 이름:
매개변수 타입...) -> 반환 타입 {

     실행구문

     return 반환 값

}

 

코드를 보면 _ (와일드카드)를 통해 다른언어처럼 매개변수를 받아올 수 있습니다.

for in문은 조건이 아니라 범위를 넣어야 함을 알 수 있습니다.

// 와일드 카드를 통해 다른언어 처럼 매개변수를 받아올 수 있습니다.
func sayHello(to name: String, _ times: Int) -> String {
    var result: String = ""
    
    //   A.. < B 0부터 times 미만의 수를 묶어표현
    // _를 사용하여 그냥 반복만 시키게 함
    for _ in 0..<times {
        result += "Hello \(name)!" + " "
    }
    
    return result
}

func sayHello(to name: String, repeatCount times: Int) -> String {
    var result: String = ""
    
    for _ in 0..<times {
        result += "Hello \(name)!" + " "
    }
    
    return result
}

// 와일드 카드를 통해 다른언어 처럼 매개변수를 받아올 수 있습니다.
print(sayHello(to: "chopes", 2))
print(sayHello(to: "chopes", repeatCount: 2))

 

가변 매개변수와 입출력 매개변수

func sayHelloToFriends(me: String, friends names: String...) -> String {
    var result: String = ""
    
    for friend in names {
        result += "Hello \(friend)!" + " "
    }
    
    result += "I'm " + me + "!"
    
    return result
}


print(sayHelloToFriends(me: "kemi", friends: "Johansson", "Jay", "Wizplan"))
// Hello Johansson! Hello Jay! Hello Wizplan! I'm kemi!

print(sayHelloToFriends(me: "kemi"))
// I'm kemi!

 

함수에 매개변수를 넣어 값을 전달할 때 값을 복사해서 전달하게 되는데 참조값을 매개변수에 전달하면 어떻게 되는지 살펴봅시다.

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

func nonReferenceParameter(_ arr: [Int]) {
    var copiedArr: [Int] = arr
    copiedArr[1] = 1
}

func referenceParameter(_ arr: inout [Int]) {
    arr[1] = 1
}

nonReferenceParameter(numbers)
print(numbers[1])

referenceParameter(&numbers)
print(numbers[1])

 

 참조 변수를 넣는다고 해도 값복사로 동작하게 됩니다. 참조 변수 값으로 유지하기 위해선 함수 argument 타입 앞에 inout 을 작성하고 파라미터로 전달 할 때는 &을 앞에 붙여주면됩니다.

스위프트는 함수형 기법을 지향하기 때문에 참조변수를 유지하는것은 사이드 이펙트가 발생할 수 있기 때문에 좋지는 않습니다. 하지만 스위프트의 기반은 객체기반이기 때문에 프레임워크에서는 자주 나오는 표현입니다.

 

일급객체 함수 

스위프트의 함수는 일급 객체이기 때문에 반환값으로 함수를 가질 수 있고 파라미터로도 함수를 가질 수 있습니다.

typealias CaculateTwoInts = (Int, Int) -> Int

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

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

var mathFunction: CaculateTwoInts = addTwoInts

print(mathFunction(2, 5))   // 7

mathFunction = multiplyTwoInts

print(mathFunction(2, 5))   // 10

 

중첩 함수

typealias MoveFunc = (Int) -> Int

func goRight(_ currentPosition: Int) -> Int {
    return currentPosition + 1
}

func goLeft(_ currentPosition: Int) -> Int {
    return currentPosition - 1
}

func functionForMove(_ shouldGoLeft: Bool) -> MoveFunc {
    return shouldGoLeft ? goLeft : goRight
}

var position: Int = 3 // 현위치

// 현 위치가 0보다 크므로 전달되는 인자 값은 true가 됩니다.
// 현재는 goLeft함수가 들어가 있습니다.
let moveToZero: MoveFunc = functionForMove(position > 0)
print("원점으로 갑시다.")

while position != 0 {
    print("\(position)...")
    // goLeft(postion)과 동일..
    position = moveToZero(position)
}

print("원점 도착")

 

중첩 함수 사용 시

typealias MoveFunc = (Int) -> Int

func functionForMove(_ shouldGoLeft: Bool) -> MoveFunc {
    func goRight(_ currentPosition: Int) -> Int {
        return currentPosition + 1
    }
    func goLeft(_ currentPosition: Int) -> Int {
        return currentPosition - 1
    }
    
    return shouldGoLeft ? goLeft : goRight
}

var position: Int = -4 // 현위치

let moveToZero: MoveFunc  = functionForMove(position > 0)

while (position != 0) {
    print("\(position)...")
    position = moveToZero(position)
}
print("원점 도착!")

 

7.4 종료되지 않는함수(비반환 함수 또는 비반환 메서드)

비반환 함수는 정상적으로 끝날 수 없는 함수입니다.

비반환 함수 안에서는 오류를 던진다든가, 중대한 시스템 오류를 보고하는 등의 일을 하고 프로세스를 종료해버리기 때문입니다.

비반환 메서드는 재정의는 할 수 있지만 비반환 타입이라는 것은 변경 할 수 없습니다.

 

반환 타입에 Never를 명시하여 사용 할 수 있습니다.

func crashAndBurn() -> Never {
    fatalError("Something very, very bad happend!")
}

//crashAndBurn() // 프로세스 종료 후 보고

func someFunction(isAllIsWell: Bool) {
    guard isAllIsWell else {
        print("마을에 도둑이 들었습니다.")
        crashAndBurn()
    }
    print("All is well")
}

someFunction(isAllIsWell: true)
someFunction(isAllIsWell: false)

 

반환  값을 무시할 수 있는 함수

func say(_ something: String) -> String {
    print(something)
    return something
}

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

// 반환 값을 사용하지 않았으므로 경고가 표시 될 수도 있다.
// 나는 뜨진 않았다.
say("hello")


// 반환 값을 사용하지 않을 수 있다고 명시하였기 때문에 경고 표시가 되지 않습니다.
discardableResultSay("hello")

 

 

일급 함수란 쉽게 말하면 함수를 객체로 받을 수도 있고, 함수를 리턴할 수 도 있는 함수입니다.
그리고 항상 입력값이 같으면 반환 값이 같은 특징을 보입니다. 이 소리는 외부에서 변경되는 값이 없다는 것이죠.
예를 들어 함수안에 글로벌 변수를 사용하게되면 글로벌 변수가 변경 될 때 마다 출력 값이 계속 바뀌겠죠.

 

공부를 하다보니 함수면 함수지 무슨 일급함수 같은게 있나 싶습니다.

var globalNum = 1

func plusFunction(number: Int) -> Int {
    let result = globalNum + number
	return result
}

plusFunction(number: 1) // 2 

globalNum = 3

plusFunction(number: 1) // 4  -> 같은 1 입력값을 넣었음에도 4가 출력됨. 일급함수 아님



Swift의 이상했던 부분 중 하다가 함수가 전달인자 레이블과 매개변수 이름을 갖는 다는 것이였는데요.

왜 이렇게 했는지 조금 의문이 갑니다. to 나 with을 전달인자로 많이 받곤 하는데 제대로 된 강의나 블로그를 찾아봐야 할 것 같습니다.

반응형