궁금한 내용을 검색해보세요!
이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.
서근 개발노트
티스토리에 팔로잉
SWIFT/Grammar

Swift : 기초문법 [ 함수 / 매개변수 / 메서드 ]

서근
QUOTE THE DAY

-
Written by SeogunSEOGUN

반응형

본 게시글은 yagom님의 Swift 프로그래밍 3판을 참고하여 작성되었습니다.

 

 

함수

함수는 특정 작업을 수행하는 '코드 조각'입니다. '독립된 기능'을 수행하는 단위인 것이죠. 함수 안에는 메서드를 포함하고 있습니다.

 

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

 

함수의 정의 및 호출

앞서 말했다시피 함수와 메서드는 정의하는 위치와 호출되는 범위만 다를뿐, 정의하는 키워드와 구현 방법은 같습니다. 조건문이나 반복문 같은 것과는 달리 함수에서는 소괄호(())를 생략할 수 없습니다.

 

swift의 함수는 재정의(오버라이드)와 중복 정의(오버로드)를 모두 지원기때문에 매개변수의 타입이 다르면 같은 이름의 함수를 여러 개 만들 수 있고, 매개변수의 개수가 달라도 같은 이름의 함수를 만들 수 있습니다. 그렇기 때문에 중간중간 이름이 같은 함수를 구현해도 오류가 발생하지 않죠!

 

기본적인 정의와 호출 방법

함수의 이름과 매개변수, 반환 타입 등을 사용하여 함수를 정의합니다.

 

함수 키워드 func

 

함수의 이름을 정해준 후 매개변수는 소괄호로 감싸줍니다. 반환 타입을 명시하기 전에는 ->를 사용하여 어떤 타입이 반환될 것인지 명시해줍니다.

 

반환 키워드 return

 

함수를 선언하는 기본 형태는 이러합니다. 

func 함수이름 (매개변수1이름: 매개변수1타입, 매개변수2이름: 매겨변수2타입 ...) -> 반환타입 {
   //함수 구현부
  return 반환값
}
func hello(name: String) -> String {
    return "안녕 \(name)!"
}

let myName: String = hello(name: "서근")
print(myName) // 안녕 서근!

/* =============== */

func introduce(blogName: String) -> String {
    //[ return "안녕하세요" + blogName + ... ] 와 같은 동작을 함
    "안녕하세요 \(blogName)에 방문해주셔서 감사드립니다!"
}

let welcome: String = introduce(blogName: "서근개발노트")
print(welcome)
// 안녕하세요 서근개발노트에 방문해주셔서 감사드립니다!

 

기본 형태는 다른 언어와 비슷합니다. 하지만 생략할 수 있거나 추가 가능한 부분을 알아보게 되면 swift에서 얼마나 다양하게 정의할 수 있는지 금방 눈치채실 수 있습니다.

 

앞으로 다양한 형태의 함수를 보겠지만 introduce(blogName:)에서 보듯이 return 키워드를 생략할 수도 있습니다. 함수 내부의 코드가 단 한 줄의 표현이고, 그 표현의 결괏값의 타입이 함수의 반환 타입과 정확히 일치한다면 retrun 키워드를 생략해도 그 표현의 결괏값이 함수의 반환 값이 됩니다!

TIP
 
 

매개변수와 전달 인자
매개변수는 함수를 정의할 때 외부로부터 받아들이는 전달 값의 이름을 의미합니다. 전달 인자, 혹은 인자는 함수를 실제로 호출할 때 전달하는 값을 의미합니다. 예를 들어 위 코드의 hello(name: String)함수에서 매개변수는 name이고, 실제 사용 시 전달받는 값인 "서근" 이 전달 인자입니다.

func findDirections(from: String, to: String, route: String = "fastest", avoidHighways: Bool = false) {
    // code here
}

위에 코드를 호출하려면 아래와 같이 작성합니다.

findDirections(from: "London", to: "Glasgow")
findDirections(from: "London", to: "Glasgow", route: "scenic")
findDirections(from: "London", to: "Glasgow", route: "scenic", avoidHighways: true)

만약 sum 이라는 함수를 만들려면 아래 코드처럼 작성하면 됩니다.

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

예시 : 멀티라인 스트링을 이용한 함수 작성 (멀티라인에 대해 알고 싶다면 여기를 클릭해주세요)

func printHelp() {
    let message = """
서근 블로그에 오신것을 환영합니다!

열심히 빡코딩해서 좋은개발자가 되도록
노력하겠습니다!
"""

    print(message)
}
printHelp()

/*서근 블로그에 오신것을 환영합니다!

열심히 빡코딩해서 좋은개발자가 되도록
노력하겠습니다!*/

 

함수 TEST: 문제를 풀려면 이곳을 클릭해주세요.

매개 변수(Parameter)

Swift의 함수는 매개변수를 어떻게 정의하냐에 따라서 모습이 크게 달라질 수 있습니다. 매개변수에 따라 함수의 모양과 기능이 어떻게 바뀌는지 알아보려고 합니다.

 

매개변수는 함수가 정의될 때 함수가 전달받게 되는 변수(상수) 혹은 그 이름입니다. Swift 함수의 매개변수 사용은 다른 언어와 다르게 특별한 기능이 있습니다.

print("Hello, world!")

이러한 방식으로 함수에 전송된 값을 매개변수라고 합니다. 자신의 함수가 매개 변수를 받아들이도록 하려면 각 매개 변수에 이름을 지정한 다음 콜론 : 을 지정한 다음 Swift에 데이터 유형을 알려야 합니다. 이 모든 것은 함수 이름 뒤의 ( ) 안에 있습니다. 예를 들어, 임의의 숫자의 제곱을 인쇄하는 함수를 작성해보겠습니다.

func square(number: Int) {
  print(number * number)
}

함수를 정해줬고 매개변수로 (number: Int) 값을 넣어줬습니다. 이제 다시 한번 매개변수를 이용하여 프린트해줘야겠죠?

square(number: 4)  //16

매개변수가 없는 함수와 매개변수가 여러 개인 함수

함수에 매개변수가 필요 없다면 매개변수 위치를 공란으로 비워둘 수 있습니다.

func helloSeogun() -> String {
    return "안녕, 서근!"
}

print(helloSeogun()) // 안녕, 서근!

매개변수가 여러 개 필요한 함수를 정의할 때는 쉼표로 매개변수를 구분할 수 있는데, 주의할 점은 함수를 호출할 때, 매개변수 이름을 붙여주고 콜론( : )을 적어준 후 전달 인자를 보내준다는 것입니다. 이렇게 매개변수 뒤에 붙는 이름을 매개변수 이름이라고 하죠.

 

여러 개의 매개변수가 있는 함수를 구현하고 사용해볼게요.

func welcome(myname: String, yourname: String) -> String {
    "안녕하세요 \(yourname)님! 저는 \(myname) 이라고 합니다!"
}

print(welcome(myname: "서근", yourname: "미진"))
// 안녕하세요 미진님! 저는 서근 이라고 합니다!

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

위에 welcome(myName: yourName:) 함수를 호출할 때 myNameyourName이 라는 매개변수 이름을 사용했죠? 매개변수 이름과 더불어 전달 인자레이블을 지정해줄 수 있습니다. 함수를 정의할때 매개변수를 정의하면 매개변수 이름과 전달인자 레이블을 같은 이름으로 사용할 수 있지만, 전달인자 레이블을 별도로 지정하면 함수 외부에서 매개변수의 역활을 좀 더 명확하게 할 수 있습니다. 전달인자 레이블을 사용하려면 함수 정의에서 매개변수 이름 앞에 한칸을 띄운 후 전달인자 레이블을 지정합니다.

func 함수이름 (전달인자 레이블1 매개변수1이름: 매개변수1타입, 전달인자 레이블2 매개변수2이름: 매겨변수2타입) -> 반환타입 {
   //함수 구현부
  return 반환값
}
// from과 to라는 전달인자레이블이 존재
// myName과 name이라는 매개변수 이름이 있는 welcome 함수
func welcome(from myname: String, to yourname: String) -> String {
    "안녕하세요 \(yourname)님! 저는 \(myname) 이라고 합니다!"
}

print(welcome(from: "서근", to: "미진"))
// 안녕하세요 미진님! 저는 서근 이라고 합니다!

위 코드에서 매개변수 이름과 전달 인자 레이블을 어떻게 사용하는지 알수 있습니다. 함수 내부에서 전달인자 레이블을 사용할 수 없으며, 함수를 호출할 때는 매개변수 이름을 사용할 수 없습니다.

 

전달인자 레이블을 사용하고 싶지 않다면 와일드카드 식별자를 사용할 수 있습니다. 

func welcome(_ myname: String, _ times: Int) -> String {
    var result: String = ""
    
    for _ in 0..<times {
        result += "안녕 \(myname)!" + " "
    }
    return result
}

print(welcome("서근", 2))

//안녕 서근! 안녕 서근!

또, 전달인자 레이블을 변경하면 함수의 이름 자체가 변경됩니다. 그렇기에 전달인자 레이블만 다르게 써주더라고 함수 중복 저의(오버로드)로 동작할 수 있습니다.

func welcome(_ myname: String, _ times: Int) -> String {
    var result: String = ""
    
    for _ in 0..<times {
        result += "안녕 \(myname)!" + " "
    }
    return result
}

print(welcome("서근", 2)) // 안녕 서근! 안녕 서근!

/* ========= */

//함수의 이름이 같지만 전달인자레이블이 다르기 때문에 함수 중복 정의(오버로드)가 가능하다.
func welcome(to name: String, repeatCount times: Int) -> String {
    var result: String = ""
    
    for _ in 0..<times {
        result += "안녕 \(name)!" + " "
    }
    return result
}

print(welcome(to: "서근", repeatCount: 2)) // 안녕 서근! 안녕 서근!

 

매개변수 기본값

Swift 함수에서는 매개변수마다 기본값을 지정할 수 있습니다. 즉, 매개변수가 전달되지 않으면 기본값을 사용합니다. 매개변수 기본값이 있는 함수는 함수를 중복 정의한 것처럼 사용할 수 있습니다.

 

바로 위에서 우리는 times 매개변수에 기본값을 3으로 주게 되면 times 매개변수를 넘겨주지 않아도 times 값을 3으로 설정해 함수가 스스로 동작합니다. 

//함수의 이름이 같지만 전달인자레이블이 다르기 때문에 함수 중복 정의(오버로드)가 가능하다.
func welcome(to name: String, repeatCount times: Int = 3) -> String {
    var result: String = ""
    
    for _ in 0..<times {
        result += "안녕 \(name)!" + " "
    }
    return result
}

print(welcome(to: "서근")) // 안녕 서근! 안녕 서근! 안녕 서근!

가변 매개변수

매개변수로 몇 개의 값이 들어올지 모를 때, 가변 매개변수를 사용합니다. 가변 매개변수는 0개 이상의 값을 받아올 수 있고, 가변 매개변수로 들어온 인자 값은 배열처럼 사용할 수 있습니다. 함수마다 가변 매개변수는 하나만 가질 수 있습니다.

func welcomeToFriends(me: String, friends name: String...) -> String {
    var result: String = ""
    
    
    for friends in name {
        result += "안녕 \(friends)아!"
    }
    
    result += "나는 " + me + "이야!"
    return result
}

print(welcomeToFriends(me: "서근", friends: "미진", "지혜", "성민"))
//안녕 미진아!안녕 지혜아!안녕 성민아!나는 서근이야!

print(welcomeToFriends(me: "서근"))
// 나는 서근이야!

 

매개변수 TEST: 문제를 풀려면 이곳을 클릭해주세요.

중첩 함수

Swift는 데이터 타입의 중첩이 자유롭습니다 = 열거형 안에 열거형, 클래스 안에 클래스 가능!

 

함수의 중첩은 함수 안에 함수를 넣을 수 있다는 의미. 우리가 앞서 살펴보았던 함수는 특별한 위치에 속해 있지 않은 한 모두 전역 함수입니다.

 

그러나 함수 안에 함수로 구현된 중첩 함수는 상위 함수의 몸통 블록 내부에서만 함수를 사용할 수 있습니다. 중첩 함수의 사용 범위가 해당 함수 안쪽이라고 해서 아예 외부에서 사용할 수 없는 것은 아닙니다. 함수의 하나의 반환 값으로 사용될 수 있으므로 중첩 함수를 담은 함수가 중첩 함수를 반환하면 밖에서도 사용할 수 있습니다.

 

예를 들어서 만약 원점이 0이고  왼쪽은 음수( - ) 오른쪽은 양수( + ) 가 있는 보드가 있다고 생각해봅시다. 이 보드판은 무조건 원점으로 돌아오는 형태입니다. 만약 음수에 위치해있으면 점점 원점으로 돌아오는 것이죠.

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 = -6

let moveToZero: MoveFunc = functionForMove(position > 0)
print("원점으로 출발!")

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

/*
 원점으로 돌아갑니다
 -6 ...
 -5 ...
 -4 ...
 -3 ...
 -2 ...
 -1 ...
 원점에 도착했습니다!
 */

이게 여태까지 우리가 함수를 구현하던 방식입니다. 그런데 왼쪽으로 이동하는 함수와 오른쪽으로 이동하는 함수는 원점으로 돌아가는 목적은 같죠? 그렇기 때문에 굳이 모듈 전역에서 사용할 필요가 없습니다.

 

그래서 사용 범위를 한정하고자 함수를 하나의 함수 안쪽으로 배치해 중첩 함수로 구현하고, 필요할 때만 외부에서 사용할 수 있도록 구현할 수 있습니다. 

typealias moveFunc = (Int) -> Int

func functionForMove(_ shouldGoLeft: Bool) -> moveFunc {
    func goToRight(_ currentPosition: Int) -> Int {
        return currentPosition + 1
    }
    
    func goToLeft(_ currentPosition: Int) -> Int {
        return currentPosition - 1
    }
    
    return shouldGoLeft ? goToLeft : goToRight
}

var position: Int = 5

let moveToZero: moveFunc = functionForMove(position > 0)

print("원점으로 출발!")

while position != 0 {
    print("\(position)...")
    position = moveToZero(position)
}

print("원점 도착!")

종료되지 않는 함수

Swift에는 종료(return) 되지 않는 함수가 존재합니다.

 

종료되지 않는다 = 정상적으로 끝날수 없는 함수 = 비반환 함수(Nonreturning function) = 비반환 메서드(Nonreturing method)

 

이 함수를 실행하게 되면 프로세스 동작은 끝났다고 보면 됩니다! 

 

비반환 함수 안에서는 오류를 throw 한다던가, 중대한 시스템 오류를 보고하는 등의 일을 하고 프로세스를 종료해버리기 때문이죠. 비반환 함수는 어디서든 호출이 가능하고 guard 구문의 else 블록에서도 호출할 수 있습니다. 비반환 메서드는 재정의는 할 수 있지만 비반환 타입이라는 것은 변경 불가능합니다.

 

키워드 Never

func crashAndBurn() -> Never {
    fatalError("Someting very bad happened")
}

crashAndBurn() //프로세스 종료 후 오류를 보고함

func someFunction(isyours: Bool) {
    guard isyours else {
        print("당신의 것이 아닙니다.")
        crashAndBurn()
    }
    print("이것은 당신의 것입니다!")
}

someFunction(isyours: true) // 이것은 당신의 것입니다!
someFunction(isyours: false) // 당신의 것이 아닙니다.
//프로세스 종료 후 오류를 보고함
func someFunction() -> Never {
    fatalError("나의 아이폰을 찾을 수 없습니다.")
}

func findMyiPhone(isFound: Bool) {
    print("isFound : \(isFound)")
    guard isFound else {
        print("나의 아이폰을 누군가 훔쳐갔습니다!")
        someFunction()
    }
    print("나의 아이폰을 찾았습니다!")
}

findMyiPhone(isFound: true)
findMyiPhone(isFound: false)

/*
 isFound : true
 나의 아이폰을 찾았습니다!
 isFound : false
 나의 아이폰을 누군가 훔쳐갔습니다!
 Fatal error: 나의 아이폰을 찾을 수 없습니다.
*/

 

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

이 함수는 반환값을 사용하지 않을 것이기 때문에 경고를 하지 않아도 돼!라는 뜻입니다. 즉, 함수의 반환 값을 무시해도 된다는 의미죠

 

"이 함수에서 반환되는 값을 무시해도 돼!" 이 함수를 사용하면 반환 값을 사용하지 않아도 경고를 보내지 않습니다.

 

키워드 @discardableResult

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

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

// 반환 값을 사용하지 않았으므로 컴파일러가 경고를 표시할 수 있음
say("hello") //hello

// 반환 값을 사용하지 않을 수 있다고 미리 알렸기 때문에
// 반환 값을 사용하지 않아도 컴파일러가 경고하지 않음
discadableResultSay("hello") // hello

반환 값(Returning Value)

함수는 데이터를 수신할 뿐만 아니라 데이터를 다시 보낼 수도 있습니다. 이렇게 하려면 함수의 매개 변수 목록 뒤에 오른쪽 화살표->를 쓴 다음 Swift에 어떤 종류의 데이터가 반환될 것인지 알려줘야 합니다.

 

함수 내에서 return 키워드를 사용하여 값이 있는 경우 값을 다시 보냅니다. 그러면 함수가 즉시 종료되고 해당 값을 다시 보냅니다.

 

해당 함수의 다른 코드는 실행되지 않습니다. 위에서 사용했던 함수 예제를 반환값를 사용하여 실행해보도록 할게요.

func square(number: Int) -> Int {
  return number * number
}

이제 함수를 실행될 때 반환 값 return 을 가져와서 출력할 수 있습니다.

func square(number: Int) -> Int{
    return number * number
}
let result = square(number: 4)
print("4의 제곱은 \(result)입니다.")  //4의 제곱은 16입니다.

여러 값을 반환해야 하는 경우 튜플을 사용해야 합니다! (name: String, age: Int)

데이터 타입으로서의 함수

앞에 말했듯이 Swift의 함수는 일급 객체 이므로 하나의 데이터 타입으로 사용할 수 있습니다. 즉, 각 함수는 매개변수 타입과 반환 타입으로 구성된 하나의 타입으로 사용할 수 있다는 뜻이죠. 함수를 하나의 데이터 타입으로 나타내는 방법은 다음과 같습니다.

(매개변수 타입의 나열) -> 반환타입

예를 들어 아래와 같은 함수가 있다고 가정할게요

func welcome(name: Stirng, times: Int) -> String {
    // 구현부
}

welcome 함수 타입이 (String, Int) -> String 이죠? 다음 함수도 살펴볼게요.

func sayHelloToFriends(me: String, names: String...) -> String {
    // 구현부
}

sayHelloToFriends 함수 타입은 (Stringm String...) -> String이네요. 만약 매개변수가 변환 값이 없다면 Void 키워드를 사용하여 반환 값이 없다고 나타낼 수 있습니다.

func Goodbye() {
    // 구현부
}

아래 반환 타입이 없는 경우에 대해 설명하겠지만 간단하게 보자면 Goodbye() 함수 타입은 (Void) -> Void 입니다. 참고로 Void 키워드를 빈 소괄호로 표현할 수 있습니다. 타음 표현은 모두 같은 표현입니다.

  • (Void) -> Void
  • () -> Void
  • () -> ()

다음은 함수를 데이터 타입으로 사용할 수 있는 간단한 예제입니다. 함수를 데이터 타입으로 사용할 수 있다는 것은 함수를 전달 인자로 받을 수도, 반환 값으로 돌려줄 수도 있다는 의미이죠. 상황에 맞는 함수를 전달인자로 넘겨서 적절히 처리할 수 있고, 상황에 맞는 함수를 반환해주는 것도 가능하다는 의미입니다. 

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: (Int, Int) -> Int = addTwoInts
var mathFunction: CalculateTwoInts = addTwoInts
print(mathFunction(2, 5)) // 2+ 5 = 7

mathFunction = multiplyTwoInts
print(mathFunction(62, 2)) // 62 * 2 = 124

먼저 두 Int값을 입력받아 계산 후 Int값을 반환해주는 형태의 함수를 CalculateTwoInts라는 별칭(typealias)으로 지었습니다. 그리고 addTwoInts(_: _:)multiplyTwoInts(_: _:) 라는 함수 두 개를 만들었죠. 두 함수는 변수 mathFunction에 번걸아 가면서 할당되거나 mathFunction이라는 이름으로 호출할 수도 있습니다.

 

그리고 아래처럼 전달 인자로 함수를 넘겨줄 수 있습니다.

func printMathResult(_ mathFunction: CalculateTwoInts, _ a: Int, _ b: Int) {
   print("결과: \(mathFunction(a, b))")
}
printMathResult(addTwoInts, 3, 5) // 결과: 8

물론 아래처럼 반환 값으로 함수를 반환할 수도 있습니다.

func printMathResult(_ mathFunction: CalculateTwoInts, _ a: Int, _ b: Int) {
   print("결과: \(mathFunction(a, b))")
}
printMathResult(addTwoInts, 3, 5)


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

printMathResult(chooseMathFunction(true), 3, 10) // 3 + 10 = 결과: 13
printMathResult(chooseMathFunction(false), 3, 10) // 3 * 10 = 결과: 30

TIP
 
 

전달 인자 레이블과 함수 타입
전달인자 레이블은 함수 타입의 구성요소가 아니므로 함수 타입을 작성할 때는 전달인자 레이블을 써줄 수 없습니다.

let someFunction: (years: Int, age: Int) -> Int // 오류
let someFunction: (_ years: Int, _ age: Int) -> Int // OK
let someFunction: (Int, Int) -> Int // OK

Return키워드가 필요하지 않은 경우는 언제??

Swift에서 값을 반환하기 위해 return값이 필요하지만, 필요하지 않은 특정한 경우가 있습니다. 바로 함수가 단일 표현식만 포함하는 경우입니다. 예를 들어보겠습니다.

5 + 8

5+813으로 단일 값이죠? 또는 아래와 같이 단순한 "서근"을 출력하는 단일 값이 있습니다.

print("서근")

더 긴 코드도 단일 값으로 해석되는 경우가 있습니다.

let isAdmin = true 
let isOwner = false
let isEditingEnabled = false

이 코드를 논리 연산자로 표현할 수 있겠네요.

isOwner == true && isAdmin || isEditingEnabled == true
//isOwner가 true이거나 isAdmin 또는 isEditingEnabled가 하나라도 true이라면

Q. 위 코드는 true 입니다. 그렇다면 isOwnerfalse 라면 true 일까요 false 일까요?

let isAdmin = true
let isOwner = false
let isEditingEnabled = false

if isOwner == true && isEditingEnabled || isAdmin == true {
    print("정답")
}

A. isOwner가 상수 false로 되어있지만 조건에는 true로 되어있습니다. 하지만 isEditingEnabled 또는 isAdmin 둘 중에 하나라도 true이면 전체 표현이 true가 됩니다.

if false && false || true

이처럼 많은 코드들을 단일 값으로 해결할 수 있습니다. 하지만 단일 값으로 해결할 수 없는 코드도 많습니다. 예를 들어

let name = "서근"

상수를 생성했지만 값이 되지는 않습니다. 그렇기 때문에 return let name = "서근" 처럼 사용할 수 없습니다.

if name == "서근" {
    print("Hello, 서근!")
}

위 코드 또한 앞에 조건 if 가 붙었기 때문에 단일 값이 될 수 없습니다.

 

⭐️중요 : 표현식은 원하는 만큼 길게 쓸 수 있지만 어떤 문 for, if, var, let)도 포함할 수 없습니다.

삼항 연산자로 표현

다음 논리 연산자 코드를 삼항 연산자로 표현도 가능합니다.

func greet(name: String) -> String {
    if name == "서근 블로그" {
        return "Oh wow!"
    } else {
        return "Hello, \(name)"
    }
}

자 여기서 return을 제거하면 오류가 발생합니다.

func greet(name: String) -> String {
    if name == "서근 블로그" {
        "Oh wow!"
    } else {
        "Hello, \(name)"
    }
}
//return이 빠졌기 때문에 런타임 오류가 생김

위 코드를 삼항연산자로 바꿔보겠습니다.

func greet(name: String) -> String {
  name == "서근 블로그" ? "Oh wow!" : "Hello, \(name)"
}

반환 타입이 없는 경우

하지만 만약에 반환타입이 없는 경우 에는 어떻게 써야 할까요?

 

첫 번째. 그럴때는 반환타입이 들어가는 부분에 Void 를 넣어주면 됩니다. 여기서 Void라는 의미 없다 라는 타입 별칭의 의미가 됩니다.

func 함수이름 (매개변수1이름: 매개변수1타입, 매개변수2이름: 매겨변수2타입 ...) -> Void {
   //함수 구현부
  return 반환값
}
func printMyName(name: String) -> Void {
  print(name)
}

두 번째. Void 부분 즉 반환타입을 생략해 줘도 됩니다.

func 함수이름 (매개변수1이름: 매개변수1타입, 매개변수2이름: 매겨변수2타입 ...) {
   //함수 구현부
}
func printYourName(name: String) {
   print(name)
}

반환 값이 없는 세 개의 함수를 구현하고 사용한 코드를 한번 살펴볼게요.

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

func welcome(me myname: String, you yourname: String) {
    print("안녕하세요 저는 \(myname) 입니다! 잘 부탁드려요 \(yourname)씨! ")
}
welcome(me: "서근", you: "미진") // 안녕하세요 저는 서근 입니다! 잘 부탁드려요 미진씨!

func sayGoodbye() -> Void {
    print("Good bye!")
}
sayGoodbye() // Good bye!

 

매개 변수가 없는 경우

매개 변수가 없다면 () 으로만 작성해주시면 됩니다. () 는 생략이 불가능합니다!

//매개변수가 없다면 ()으로 작성
func 함수이름() -> 반환타입 {
    //함수 구현부
   return 반환값 
}
func maximumIntegerValue() -> Int {
    return Int.max
 }

매개변수와 반환 값이 둘 다 없는 경우

위에서 배운 것을 조합하면 되는데,

첫 번째. 매개변수에 ()를 넣고 반환값에 -> Void 를 추가합니다.

func 함수이름() -> Void {
    //함수 구현부
}
//반환값이 없어 코드가 짧다면 이렇게 한줄로 표현하는것이 좋습니다.
func hello() -> Void { print("hello") }

두 번째. 반환값의 Void를 생략합니다.

func 함수이름() {
    //함수 구현부
}
func bye() { print("bye") }

자, 이렇게 만들어 놓은 함수를 호출하는 방법은 아래와 같습니다.

//MARK: 함수 호출
sum(a: 1, b: 6) // 7

printMyName(name: "SeoGun") // SeoGun

printYourName(name: "KiKi") // KiKi

maximumIntegerValue() // Int의 최댓값

hello() // hello

bye() // bye

함수에서 두 개 이상의 값을 반환하려면??

함수에서 두 개 이상의 값을 반환하기 위해서는 두 가지 방법이 있습니다.

튜플에 대해 아직 이해하기 어렵다면 아래에 쉬운 예를 보면서 다시 알아보겠습니다. 사람의 이름과 성을 반환하는 함수를 만들고 싶다면 아래와 같이 작성할 수 있습니다.

func getUser() -> [String] {
    ["김", "서근"]
}

let user = getUser()
print(user[0])

이 코드는 무엇이 문제일까요? 두 가지의 문제점이 있습니다.

 

첫 번째, 한국이 아닌 다른 나라에서는 먼저 이름을 작성하고 그 뒤에 성을 작성하는 곳도 있습니다. 인텍스[0] 이 이름이고 인덱스[1] 이 성 이 될 수 있죠.

두 번째, 중간에 이름을 삽입해야 할 수 도 있습니다. 그렇다고 인텍스[1]을 인덱스인텍스[2]로 바꾸면 오류가 생기게 됩니다.

그래서 다음과 같이 코드를 작성해줄 수 있습니다. Playground에서 아래 코드를 실행해보면 오류가 발생하죠?

func getUser() -> [String] {
  ["first": "김", "last": "서근"]
}
/*Cannot convert return expression of type '[String : String]' to return type '[String]'
 [String : String] 유형을 [String]반환 형식으로 변환 할 수 업습니다. */

let user = getUser()
print(user["first"])

튜플이름, 유형, 순서 등 어떤 데이터가 return되는지 구체적으로 지정하여 문제를 해결할 수 있습니다. 즉, 훨씬 더 안전하게 여러 값을 반환하는 함수를 작성할 수 있습니다.

func getUser() -> (first: String, last: String) {
    (first: "김", last: "서근")
}

let user = getUser()
print(user.first)

이제 우리는 위에서 겪었던 문제들을 모두 해결했습니다.

  • 성을 first로 두고 이름을 last로 순서에 반환되었습니다.
  • 중간에 이름을 삽입해도 다른 값의 위치에 영향을 주지 않습니다.
  • 값을 읽는 동안 대소문자를 구분하는 실수를 할 수 없습니다.
  • 누군가가 하나의 성이나 이름 둘 중에 하나만 사용하면 빈 문자열이 반환됩니다.

따라서 튜플을 사용하는 것이 함수에서 여러 값을 반환하는 아주 좋은 방법입니다.

 

반환 값 함수 TEST: 문제를 풀려면 이곳을 클릭해주세요.

메서드(Method)

Class(클래스), Struct(구조체), Enum(열거형)에 표함 되어있는 '함수'를 메서드라고 합니다.

메서드는 다른 말로 '클래스 함수'라고도 합니다.

class Person { 

//이 메서드는 person 타입에만 작동(적용)됩니다.
  func personGreeting() { 
      greet(yourName: "Santosh", category: .Person)
  } 
} 

즉, 클래스 안에 작성되는 함수는 이제 무조건 '메서드'가 됩니다.

func someFunction {
  //함수 구현부
}

class someClass {

   func someMethod {
   //메서드 구현부
   }

}

 

읽어주셔서 감사합니다🤟

 

 


잘못된 내용이 있으면 언제든 피드백 부탁드립니다.


서근


위처럼 이미지 와 함께 댓글을 작성할 수 있습니다.