함수

hoBahk·2021년 6월 29일
0

함수와 메서드

함수와 메서드는 기본적으로 같다. 상황이나 위치에 따라 다른 용어로 부른다.
구조체, 클래스, 열거형 등 특정 타입에 연관되어 사용하는 함수를 메서드
모듈 전체에서 전역적으로 사용할 수 있는 함수를 함수
즉, 함수가 위치하거나 사용되는 범위 등에 따라 호칭이 달라질 뿐이다.

1. 함수의 정의와 호출

함수에서는 소괄호를 생략할 수 없다.
재정의(오버라이드)와 중복정이(오버로드)를 모두 지원한다.
따라서 매개변수의 타입이 다르면 같은 이름의 함수를 여러 개 만들 수 있고, 매개변수의 개수가 달라도 같은 이름의 함수를 만들 수 있다.

ex) 기본 형태의 함수 정의와 사용

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

let helloJoy: String = hello(name: "Joy")

print(helloJoy)

func introduce(name: String) -> String{
    "my name is" + name  // = return "my name is" + name
}
let introduceJoy: String = introduce(name: "Joy")
print(introduceJoy)

1) 매개변수

매개변수는 함수를 정의할 때 외부로부터 받아들이는 전달 값의 이름을 의미한다. 전달인자(Argument) 혹은 인자는 함수를 실제로 호출할 때 전달하는 값을 의미한다.

  • 매개 변수가 없는 함수와 매개변수가 여러 개인 함수
    ex) 매개변수가 없는 함수의 정의와 사용
func helloWorld() -> String {
    return "Hello World!"
}

print(helloWorld())

ex) 매개변수가 여러 개인 함수의 정의와 사용

func sayHello(myName: String, yourname: String) -> String{
    return "Hello \(yourname) I',m \(myName)"
}
print(sayHello(myName: "Joy", yourname: "may"))

ex) 매개변수의 이름과 전달인자 레이블을 가지는 함수 정의와 사용

func sayHello(from myName:String, to name: String) -> String {
    return "Hello \(name)! I'm \(myName)"
}
print(sayHello(from: "Joy", to: "may"))

ex) 전달인자 레이블이 없는 함수 정의와 사용

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

print(sayHello("Joy", 3))

ex) 전달인자 레이블 변경으로 통한 함수 중복 정의

func sayHello(to name:String, _ times:Int) -> String{
    var result: String = ""
    
    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: "Chope", 2))
print(sayHello(to: "Chope", repeatCount: 2))

ex) 매개변수 기본값이 있는 함수의 정의와 사용

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

print(sayHello("Joy", 2))
print(sayHello("Joy"))
//Hello Joy! Hello Joy!
//Hello Joy! Hello Joy! Hello Joy!

ex) 가변 매개변수를 가지는 함수의 정의와 사용

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: "Joy", friends: "A", "B", "C"))
//Hello A! Hello B! Hello C! I'm Joy!
print(sayHelloToFriends(me: "Joy"))
//I'm Joy!

ex) inout 매개변수의 활용

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])
//2
//1

2) 반환이 없는 함수

리턴 값이 없는 함수

ex) 반환 값이 없는 함수의 정의와 사용

func sayHelloWorld(){
    print("Hello, world!")
}
sayHelloWorld() // Hello, World!

func sayHello(from myName: String, to name: String){
    print("\(myName) \(name)")
}
sayHello(from: "Joy", to: "may")//Joy, may

func sayGoodbye() -> Void{
    print("Bye")
}

sayGoodbye()// Bye

3) 데이터 타입으로서의 함수

함수는 일급 객체이므로 데이터 타입으로 사용할 수 있다.

ex) 함수를 데이터 타입으로 나타내는 방법

func sayHello(name: String, times: Int) -> String{
    // sayHello함수의 타입은 (String, Int) -> String 이다.
    let exString:String = ""
    return exString
}


func sayHelloFriends(me: String, names: String...) -> String{
    //sayHelloFriends 함수의 타입은(String, String) -> String이다.
    let exString:String = ""
    return exString
}

func sayHelloWorld(){
    //sayHelloWorld의 타입
    //(Void) -> Void
    //() -> Void
    //() -> ()
}

ex) 함수 타입의 사용

typealias CalculateTwoints = (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: CalculateTwoints = addTwoInts

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

mathFunction = multiplyTwoInts
print(mathFunction(2,3))//6

ex) 전달인자로 함수를 전달받는 함수

typealias CalculateTwoints = (Int, Int) -> Int

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

func printMathResult(_ mathFunction: CalculateTwoints, _ a: Int, _ b: Int) {
    print(mathFunction(a,b))
}

printMathResult(addTwoInts, 2, 3) // 5

ex) 특정 조건에 따라 적절한 함수를 반환해주는 함수

typealias CalculateTwoints = (Int, Int) -> Int

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

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

func printMathResult(_ mathFunction: CalculateTwoints, _ a: Int, _ b: Int) {
    print(mathFunction(a,b))
}

printMathResult(addTwoInts, 2, 3)

func chooseMathFunction(_ toAdd: Bool) -> CalculateTwoints{
    return toAdd ? addTwoInts : multiplyTwoInts
}

printMathResult(chooseMathFunction(true), 2, 3) //5

✓ 전달인자 레이블과 함수 타입

전달인자 레이블은 함수 타입의 구성요소가 아니므로 함수 타입을 작성할 때는 전달인자 레이블을 쓸 수 없다.
let someFunction: (lhs: Int, rhs:Int) -> Int //error
let someFunction: (Int, Int) -> Int //OK
let someFunction: ( lhs: Int, rhs: Int) -> Int //OK

2. 중첩 함수

ex)원점으로 이동하기 위한 함수

typealias MoveFunc = (Int) -> Int

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

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

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

var position: Int = 3
let moveToZero: MoveFunc = funtionMove(position>0)
print("원점으로 가보쟈")

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

ex) 중첩함수의 사용

typealias MoveFunc = (Int) -> Int
func funtionMove(_ 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 = -5
let moveToZero: MoveFunc = funtionMove(position>0)
print("원점으로 가보쟈")

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

3. 종료되지 않는 함수

종료되지 않는다는 의미는 정상적으로 끝나지 않는 함수라는 뜻이다.
이를 비반환 함수(Nonreturning function) 또는 비반환 메서드(Nonreturning method)라고 한다.
비반환 함수(메서드)는 정상적으로 끝날 수 없는 함수이다.
비반환 함수 안에는 오류를 던진다던가 중대한 시스템 오류를 보고하는 등의 일을 하고 프로세스를 종료한다.
비반환 함수는 어디에서든 호출이 가능하고 guard구문의 else 블록에서도 호출할 수 있다.
비반환 메서드는 재정의는 할 수 있지만 비반환 타입이라는 것은 변경할 수 없다.
비반환 함수(메서드)는 반환 타입을 Never라고 명시해주면 된다.

ex) 비반환 함수의 정의와 사용

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) //All is well
someFunction(isAllIsWell: false) // 마을에 도둑이 들었습니다. 출력 후 프로세스 종료 후 오류 보고

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

의도적으로 함수의 반환 값을 사용하지 않을 경우 컴파일러가 함수의 결과 값을 사용하지 않았다는 경고를 보내는 것을 @discardableResult를 선언하여 막을 수 있다.

ex) @discardableResult 선언 속성 사용

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

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


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


discardableResultSay("hello")
//반환값을 사용하지 않는다고 미리 알렸기 때문에 경고 표시 되지 않는다.
profile
호박에 줄 그어서 수박 되는 성장 드라마

0개의 댓글