TIL: 함수(Function)

Royce·2025년 3월 14일

Swift 문법

목록 보기
11/63

함수(Function)

  • 함수(Function)는 특정 작업을 수행하는 코드 블록이다
  • Swift에서 함수를 사용하면 코드를 재사용할 수 있고, 더 깔끔하고 유지보수하기 쉬운 코드를 작성할 수 있다

함수는 항상 "정의(Definition)"와 "호출(Call)"로 사용된다

  • 함수의 정의(Definition): func 키워드를 사용하여 함수를 만들고, 어떻게 동작할 것인지 정의
  • 함수 호출(Call): 정의된 함수를 실행하기 위해 호출
// 1. 함수 정의
func sayHello() {
    print("Hello, Swift!")
}

// 2. 함수 호출
sayHello()  // Hello, Swift!

함수의 기본 구조

func 함수이름(파라미터: 파라미터타입) -> 반환타입 {
    // 실행할 코드
    return 결과값
}
  • 함수이름: 함수를 호출할 때 사용하는 이름
  • 파라미터(매개변수): 함수가 받을 입력값 (없을 수도 있다)
  • -> 반환타입(리턴타입): 함수가 반환하는 값의 타입(없으면 Void 또는 () 사용)
  • return: 결과를 반환할 때 사용 (반환 타입이 Void인 경우 생략 가능)

1. 파라미터가 없는 함수

  • 파라미터(매개변수)가 필요하지 않을 경우, 빈 괄호 ()를 사용한다
// 함수 정의
func sayHello() {
    print("Hello, Swift!")
}

// 함수 호출
sayHello()  // Hello, Swift!

2. 파라미터가 있는 함수

// 함수 정의
func greet(name: String) {
    print("안녕하세요, \(name)님!")
}

// 함수 호출
greet(name: "지수")  // 안녕하세요, 지수님!

3. 파라미터와 반환값이 있는 함수

// 함수 정의: 두 개의 정수를 받아서 더한 값을 반환
func add(a: Int, b: Int) -> Int {
	var c = a + b
    return c    // 아웃풋이 있는 경우, return 키워드를 사용해야 한다
}

// 함수 호출: 호출할 때는 add(a: 3, b: 5)처럼 파라미터 값(Argument)을 전달
let result = add(a: 3, b: 5)
print(result)  // 8

함수의 파라미터(Parameter)와 아규먼트(Argument)

  • Swift에서 함수를 사용할 때 "파라미터(Parameter)"와 "아규먼트(Argument)" 개념을 정확히 이해하는 것이 중요하다

1. 파라미터(Parameter)와 아규먼트(Argument)의 차이

용어설명
Parameter(파라미터)함수를 정의할 때 입력을 받을 변수
Argument(아규먼트)함수를 호출할 때 실제로 전달하는 값

즉, 파라미터는 함수 선언 시 정의되는 변수, 아규먼트는 함수 호출 시 전달하는 실제 값이다

2. 파라미터와 아규먼트의 예시

// 함수 정의 (파라미터: "name")
func greet(name: String) {
    print("안녕하세요, \(name)님!")
}

// 함수 호출 (아규먼트: "Royce")
greet(name: "Royce")


// 실행 결과
안녕하세요, Royce!
  • name: String -> 파라미터(Parameter) (함수를 정의할 때 사용)
  • "Royce" -> 아규먼트(Argument) (함수를 호출할 때 전달하는 값)

함수에서 파라미터를 설정하는 다양한 방법

1. 여러 개의 파라미터 사용

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

let result = add(a: 3, b: 5) // 아규먼트: 3, 5
print(result)  // 8
  • a: Int, b: Int -> 두 개의 파라미터
  • add(a: 3, b: 5) -> 아규먼트: 3, 5 전달

2. 기본값이 있는 파라미터(Default Parameter)

  • 기본값을 지정하면 호출할 때 값을 생략할 수 있다
func introduce(name: String, age: Int = 20) {
    print("이름: \(name), 나이: \(age)")
}

// 기본값을 사용하여 age 생략 가능
introduce(name: "Royce")         // 이름: Royce, 나이: 20
introduce(name: "Steve", age: 25) // 이름: Steve, 나이: 25
  • age: Int = 20 -> 기본값 20을 설정
  • introduce(name: "Royce") 처럼 호출 시 age를 생략하면 기본값 20이 사용된다

3. 가변 매개변수(Variadic Parameter)

  • 가변 매개변수를 사용하면 여러 개의 값을 한 번에 전달할 수 있다
func sum(numbers: Int...) -> Int {
    var total = 0
    for num in numbers {
        total += num
    }
    return total
}

print(sum(numbers: 1, 2, 3, 4, 5)) // 15
  • number: Int... -> 여러 개의 Int 값을 받을 수 있다
  • 호출 시 sum(numbers: 1, 2, 3, 4, 5) 처럼 여러 개의 아규먼트를 전달할 수 있다

아규먼트 레이블(Argument Label)

  • Swift에서는 함수를 호출할 때 파라미터를 어떻게 전달할지 지정하는 아규먼트 레이블(Argument Label)을 사용할 수 있다

1. 기본적인 아규먼트 레이블

func greetUser(to name: String) {
    print("안녕하세요, \(name)님!")
}

// 함수 호출 시 "to"를 사용
greetUser(to: "Royce")  // 호출 방식
  • to -> 아규먼트 레이블
  • name: String -> 파라미터 이름
  • 아규먼트 레이블을 사용하는 이유
    • 함수를 더 읽기 쉽게 만들기 위해 사용
    • greetUser(to: "Royce") 처럼 더 자연스러운 문장 구조로 만들 수 있다

2. 아규먼트 레이블 생략(_ 사용(와일드 카드 패턴))

  • 아규먼트 레이블을 사용하고 싶지 않을 때는 _ 를 사용해 생략할 수 있다
func greetUser(_ name: String) {
    print("안녕하세요, \(name)님!")
}

greetUser("Royce")  // 호출 방식
  • _ name: String 처럼 _ 를 사용하면 함수 오출 시 "Royce"만 전달하면 된다

3. 내부와 외부에서 다른 이름 사용

  • 함수 내부에서 사용할 변수명(파라미터 이름)과 함수 호출 시 사용할 레이블(아규먼트 레이블)을 다르게 설정할 수 있다
func calculateSum(of a: Int, and b: Int) -> Int {
    return a + b
}

let total = calculateSum(of: 3, and: 5)  // 호출 방식
print(total)  // 8
  • of a: Int, and b: Int
    • of, and -> 아규먼트 레이블 (함수 호출 시 사용)
    • a, b -> 파라미터 (함수 내부에서 사용)

함수 사용 시 주의점

1. 함수의 파라미터에 대한 정확한 이해

func someAdd(a: Int) -> Int {    // 여기서 파라미터 a는 let a: Int로 선언된 것과 동일하므로 값의 변경이 불가능하다
	a += 1    // 따라서 이와 같이 변수처럼 사용할 수 없다
	return a
}

someAdd(a: 5)

2. 함수 내의 변수의 Scope(범위)

  • 함수 내에서 선언한 변수의 Scope(범위)는 함수의 바디로 제한된다
func sumOfNum(a: Int) -> Int {
	var sum = 0
	sum += a
	return sum
}

sum = 10  // 이와 같이 함수 바깥에서 함수 내에서 정의한 sum의 값을 변경하는 것은 불가능하다

sumOfNum(a: 3)

3. return 키워드의 정확한 이해

  • return 키워드의 역할
    • 리턴 타입이 있는 함수의 경우(아웃풋이 있는 경우): return키워드 다음의 표현식을 평가한 다음, 그 결과를 리턴하면서 함수를 벗어난다
    • 리턴 타입이 없는 함수의 경우(아웃풋이 없는 경우): 함수의 실행을 중지하고 함수를 벗어난다
// 리턴 타입이 있는 경우
func addFunction(num1: Int, num2: Int) -> Int {
	var result = num1 + num2
	return result
}

addFunction(num1: 3, num2: 4)



// 리턴 타입이 있는 경우
func valuationFuncton(num: Int) -> Int {

	if num >= 5 {
    	return num
    }
    
	return 0
}

valuationFunction(num: 3)
valuatonFunction(num: 5)



// 리턴 타입이 없는 경우
func numberPrint(n num: Int) {

	if num >= 5 {
    	print("숫자가 5 이상입니다.")
    	return    // 리턴 타입이 없으므로 함수의 실행을 중지하고 함수를 벗어난다는 의미이다
    }
    
    print("숫자가 5 미만 입니다.")
}

numberPrint(n: 4)
numberPrint(n: 5)

함수의 중첩 사용 - 중첩된 함수 (Nested Function)

  • 함수 안에 함수를 작성할 수도 있다
  • 함수 안에 있는 함수는 밖에서 사용이 불가능하다
  • 함수를 제한적으로 사용하고 싶을 때 사용한다
func chooseStepFunction(backward: Bool, value: Int) -> Int {
	func stepForward(input: Int) -> Int {
    	return input + 1
    }
    func stepBackward(input: Int) -> Int {
    return input - 1
    }
    
    if backward {
    	return stepBackward(input: value)
    } else {
    	return stepForward(input: value)
    }
}

var value = 7

// case1
chooseStepFunction(backward: true, value: value)


// case2
chooseStepFunction(backward: false, value: value)

함수의 표기법(함수를 지칭 시)

1. 파라미터가 없는 경우, ()를 삭제

func doSomething() {
	print("출력")
}


doSomething // 함수 호출

2. 아규먼트 레이블이 있는 경우, 아규먼트 레이블까지를 함수의 이름으로 본다

numberPrint(n:)  // numberPrint n 함수이다

3. 파라미터가 여러 개인 경우, 콤마 없이 아규먼트 이름과 콜론을 표기

chooseStepFunction(backward:value:)

4. 아규먼트 레이블이 생력된 경우, 아래와 같이 표기

addPrintFunction(_:_:)

함수 타입의 표기

  • Swift에서 함수도 하나의 데이터 타입처럼 취급된다
  • 즉, 함수를 변수에 저장하거나, 파라미터 또는 반환값으로 사용할 수 수 있다

1. 함수 타입 기본 구조

(파라미터 타입) -> 반환 타입

// 예를 들어
func add(a: Int, b: Int) -> Int
// 는 아래처럼 함수 타입을 가진다
(Int, Int) -> Int

2. 함수 타입을 변수에 저장

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

// 함수 타입을 변수에 저장
var mathFunction: (Int, Int) -> Int = multiply

// 변수로 함수 호출 가능
print(mathFunction(3, 4))  // 12
  • multiply 함수는 (Int, Int) -> Int 타입
  • mathFunction 변수에 할당하여 함수처럼 호출 가능

3. 함수 타입을 매개변수로 사용

  • 함수를 다른 함수의 매개변수로 전달할 수도 있다
func applyFunction(_ operation: (Int, Int) -> Int, a: Int, b: Int) -> Int {
	return operation(a, b)
}

// 함수 호출 시 다른 함수를 전달
print(applyFunction(multiply, a: 3, b: 4))  // 12
  • applyFunction 함수는 operation 이라는 함수를 파라미터로 받는다
  • applyFunction(multiply, a: 3, b: 4) 처럼 다른 함수를 전달 가능하다

4. 함수 타입을 반환값으로 사용

  • Swift에서는 함수가 다른 함수를 반환할 수도 있다
func chooseOperation(isAdd: Bool) -> (Int, Int) -> Int {
    func add(a: Int, b: Int) -> Int { return a + b }
    func multiply(a: Int, b: Int) -> Int { return a * b }
    
    return isAdd ? add : multiply
}

// add를 반환받음
let operation = chooseOperation(isAdd: true)
print(operation(3, 4))  // 7
  • chooseOperation 함수는 다른 함수를 반환하는 함수
  • isAdd: trueadd 함수를 반환, falsemultiply 반환

함수의 오버로딩(Function Overloading)

  • 함수 오버로딩이란 같은 이름의 함수를 여러 개 정의할 수 있는 기능이다
  • Swift에서 함수 오버로딩은 같은 이름의 함수를 파라미터의 개수, 타입, 아규먼트 레이블이 다르게 정의하는 기능이다
  • 이렇게 하면 같은 이름의 함수라도 다양한 상황에 맞춰 사용할 수 있어 코드가 더 직관적이게 된다

1. 함수 오버로딩의 규칙

  • 함수 오버로딩이 가능하려면 아래 중 하나라도 달라야 한다
  1. 파라미터 개수가 다름
  2. 파라미터 타입이 다름
  3. 아규먼트 레이블(Argument Label)이 다름

※ 단, 반환타입만 다르면 오버로딩이 불가능하다!

2. 함수 오버로딩의 예

  1. 매개변수 개수가 다른 경우 ✅
func greet() {
    print("안녕하세요!")
}

func greet(name: String) {
    print("안녕하세요, \(name)님!")
}

// 함수 호출
greet()           // 안녕하세요!
greet(name: "Royce")  // 안녕하세요, Royce님!
  • greet() -> 파라미터가 없음
  • greet(name: String) -> 파라미터가 하나 있음
  • 같은 greet() 이름이지만, 파라미터 개수가 다르므로 오버로딩 가능 ✅

  1. 파라미터 타입이 다른 경우 ✅
func printValue(value: Int) {
    print("정수 값: \(value)")
}

func printValue(value: String) {
    print("문자열 값: \(value)")
}

// 함수 호출
printValue(value: 10)       // 정수 값: 10
printValue(value: "Hello")  // 문자열 값: Hello
  • printValue(value: Int) -> 정수를 받음
  • printValue(value: String) -> 문자열을 받음
  • 파라미터 타입이 다르므로 오버로딩 가능 ✅

  1. 아규먼트 레이블이 다른 경우 ✅
func describe(person name: String) {
    print("이 사람의 이름은 \(name)입니다.")
}

func describe(job name: String) {
    print("이 직업의 이름은 \(name)입니다.")
}

// 함수 호출
describe(person: "Royce")  // 이 사람의 이름은 Royce입니다.
describe(job: "개발자")   // 이 직업의 이름은 개발자입니다.
  • description(person name: String) -> 아규먼트 레이블이 person
  • description(jop name: String) -> 아규먼트 레이블이 job
  • 아규먼트 레이블이 다르므로 오버로딩 가능 ✅

  1. 반환 타입만 다르면 오버로딩 불가능 ❌
func getNumber() -> Int {
    return 10
}

func getNumber() -> Double {
    return 10.5
}

// ❌ 컴파일 에러 발생: "Invalid redeclaration of 'getNumber()'"
  • 반환 타입만 다를 경우는 오버로딩 불가능 ❌
  • 함수 호출 시 getNumber()만 사용하면 Swift가 어떤 함수를 실행할지 모호해지기 때문

3. 함수 오버로딩을 활용하는 방법

  1. 다양한 타입을 지원하는 함수 만들기
func square(_ value: Int) -> Int {
    return value * value
}

func square(_ value: Double) -> Double {
    return value * value
}

// 함수 호출
print(square(4))     // 16 (Int)
print(square(3.5))   // 12.25 (Double)
  • square(Int)square(Double) 을 따로 정의하면 같은 함수 이름을 유지하면서도 다른 타입 지원 가능

  1. 기본값과 오버로딩을 함께 사용
func introduce(name: String, age: Int = 20) {
    print("이름: \(name), 나이: \(age)")
}

func introduce(name: String) {
    print("이름: \(name)")
}

// 함수 호출
introduce(name: "Royce")        // introduce(name: String) 실행
introduce(name: "Steve", age: 25)  // introduce(name: String, age: Int) 실행
  • introduce(name: String) 함수가 존재하므로, introduce(name: "Royce") 호출 시 기본값이 설정된 함수 (age: Int = 20) 가 아니라 단순한 name 만 받는 함수가 실행된다
profile
iOS 개발자 지망생

0개의 댓글