1. Defining and Calling Functions πŸ‘©β€πŸ’»

Syntax

func name (parameters) -> return type {
    function body
}
  • Name: ν•¨μˆ˜λ₯Ό μ •μ˜ν•  λ•Œ μž‘μ„±ν•œλ‹€. ν•¨μˆ˜λ₯Ό μ •μ˜ν•˜κ³  ν˜ΈμΆœν•  λ•Œ μ‚¬μš©ν•˜κΈ° μœ„ν•œ ν•„μˆ˜ μš”μ†Œλ‹€.
  • Parameters(Optional): ν•¨μˆ˜λ₯Ό μ •μ˜ν•  λ•Œ μž‘μ„±ν•œλ‹€. ν•¨μˆ˜κ°€ 싀행될 λ•Œ μž…λ ₯λ˜μ–΄ λ‚΄λΆ€μ—μ„œ μ‚¬μš©ν•  κ°’λ“€λ‘œ, ν•˜λ‚˜ λ˜λŠ” κ·Έ 이상 μ •μ˜ν•  수 μžˆλ‹€.
  • Return Type(Optional): ν•¨μˆ˜λ₯Ό μ •μ˜ν•  λ•Œ μž‘μ„±ν•œλ‹€. ν•¨μˆ˜κ°€ 싀행을 마치고 μ’…λ£Œλ˜λ©° λ°˜ν™˜ν•  κ°’μœΌλ‘œ, 단 ν•˜λ‚˜μ˜ νƒ€μž…μ„ μ •μ˜ν•  수 μžˆλ‹€.
  • Arguments(Optional): ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•  λ•Œ μž‘μ„±ν•œλ‹€. ν•¨μˆ˜λ₯Ό μ‹€ν–‰ν•˜κΈ° μœ„ν•΄ ν•¨μˆ˜ μ™ΈλΆ€μ—μ„œ μ „λ‹¬ν•˜λŠ” κ°’μœΌλ‘œ, λ°˜λ“œμ‹œ Parameters의 μˆœμ„œ 및 νƒ€μž…κ³Ό μΌμΉ˜ν•΄μ•Όν•œλ‹€.


1 ) Defining Functions

func greet(person: String) -> String {
    "Hello, \(person)!"
}


2 ) Calling Functions

print(greet(person: "Anna"))    // Hello, Anna! 

ν•¨μˆ˜μ˜ Name, Parameters, Return Type은 ν•¨μˆ˜κ°€ 무슨 일을 할지, 무엇을 μž…λ ₯ 받을지, 무엇을 λ°˜ν™˜ 할지λ₯Ό μ„€λͺ…ν•˜λŠ” μ •λ³΄μ΄λ―€λ‘œ λͺ…ν™•νžˆ μž‘μ„±ν•˜λ„λ‘ ν•œλ‹€.


2. Function Parameters and Return Values πŸ‘©β€πŸ’»

1. Functions without Parameters

func sayHelloWorld() -> String {
    "hello, world"
}

print(sayHelloWorld())  // hello, world

2. Functions with Multiple Parameters

func greet(person: String) -> String {
    "Hello, \(person)!"
}

func greetAgain(person: String) -> String {
    "Hello again, \(person)!"
}
func greet(person: String, alreadyGreeted: Bool) -> String {
    if alreadyGreeted {
        return greetAgain(person: person)
    } else {
        return greet(person: person)
    }
}

print(greet(person: "Tim", alreadyGreeted: false))  // Hello, Tim!
print(greet(person: "Tim", alreadyGreeted: true))   // Hello again, Tim!

μœ„ μ½”λ“œ λΈ”λŸ­μ—μ„œ μ •μ˜ν•œ func greet(person: String) -> String와
μ•„λž˜ μ½”λ“œλΈ”λŸ­μ—μ„œ μ •μ˜ν•œ func greet(person: String, alreadyGreeted: Bool) -> String은 λ‹€λ₯Έ ν•¨μˆ˜λ‹€.

ν•¨μˆ˜ name이 같더라도 parametersκ°€ λ‹€λ₯΄λ©΄, λ‹€λ₯Έ ν•¨μˆ˜λ‘œ κ΅¬λΆ„λœλ‹€. 이λ₯Ό Polymorphism(λ‹€ν˜•μ„±)이라고 ν•œλ‹€.
단, μ΄λŸ¬ν•œ ꡬ뢄에 return type은 영ν–₯을 주지 μ•ŠλŠ”λ‹€.

3. Functions without Return Values

Return Type 이 없을 λ•ŒλŠ” Voidλ₯Ό Return Type 으둜 μ •μ˜ν•œλ‹€.

func greetVoid(person: String) -> Void {
    print("Hello, \(person)!")
}


Return Type 은 Void일 λ•Œ ν•œν•˜μ—¬ μƒλž΅λ  수 μžˆλ‹€(It implicitly returns Void).

func greetVoid(person: String) {
    print("Hello, \(person)!")
}

greetVoid(person: "Harry")  // Hello, Harry!

μ—„λ°€νžˆ λ§ν•˜λ©΄ Return Type 을 μƒλž΅ν•˜λ”λΌλ„ ν•¨μˆ˜λŠ” VoidλΌλŠ” νƒ€μž…μ˜ νŠΉμˆ˜ν•œ 값을 λ°˜ν™˜ν•œλ‹€.
이 값은 ()둜 쓰여진 Empty Tuple이닀.


λͺ…μ‹œμ μœΌλ‘œ λ°˜ν™˜ 값이 μžˆλŠ” ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•  λ•ŒλŠ” λ°˜λ“œμ‹œ let, var 둜 λ°›μ•„μ•Ό ν•œλ‹€. 그렇지 μ•ŠμœΌλ©΄ compile-time errorκ°€ λ°œμƒν•œλ‹€.
λ§Œμ•½, ν•¨μˆ˜μ˜ λ°˜ν™˜κ°’μ„ μ‚¬μš©ν•  ν•„μš”κ°€ μ—†λ‹€λ©΄ κ°„λ‹¨νžˆ _둜 λ°›μœΌλ©΄ λœλ‹€.

func printAndCount(string: String) -> Int {
    print(string)
    return string.count
}
func printWithoutCounting(string: String) {
    let _ = printAndCount(string: string)
}

print(printWithoutCounting(string: "hello, world"))
hello, world
()

4. Functions with Multiple Return Values

Swift λŠ” tuple을 μ΄μš©ν•΄ ν•˜λ‚˜μ˜ compound 둜 μ—¬λŸ¬ λ³€μˆ˜μ— 값을 ν• λ‹Ήν•  수 μžˆλ‹€.

let (alphabetA, alphabetB) = ("A", "B")
print("alphabetA is \(alphabetA) and alphabetB is \(alphabetB)")
alphabetA is A and alphabetB is B


One compound return value : λ§ˆμ°¬κ°€μ§€λ‘œ ν•¨μˆ˜μ˜ λ°˜ν™˜κ°’ μ—­μ‹œ tuple을 μ΄μš©ν•΄ μ—¬λŸ¬ 값을 ν•˜λ‚˜μ˜ compound 둜 λ°˜ν™˜ν•  수 μžˆλ‹€.

let intArray: [Int] = [31, 6, 43, 13, 6, 1, 56, 5, 88, 24]

func minMax(array: [Int]) -> (Int, Int) {
    var currentMin = array[0]
    var currentMax = array[0]
    for value in array[1..<array.count] {
        if value < currentMin {
            currentMin = value
        } else if value > currentMax {
            currentMax = value
        }
    }
    return (currentMin, currentMax)
}


1 ) λ°˜ν™˜κ°’μ„ tuple을 μ΄μš©ν•΄ 각각 Int νƒ€μž…μ˜ μƒμˆ˜ minNumber, maxNumber에 ν• λ‹Ήν•œλ‹€

let (minNumber, maxNumber): (Int, Int) = minMax(array: intArray)
print("min is \(minNumber) and max is \(maxNumber)")
min is 1 and max is 88


2 ) λ°˜ν™˜κ°’μ„ tuple νƒ€μž…μ˜ 단일 μƒμˆ˜ bounds에 κ·ΈλŒ€λ‘œ ν• λ‹Ήν•œλ‹€. 그리고 각 tuple μ—λŠ” min, max λΌλŠ” label을 λΆ™μ—¬μ€€λ‹€

let bounds: (min: Int, max: Int) = minMax(array: intArray)
print("min is \(bounds.min) and max is \(bounds.max)")
min is 1 and max is 88


3 ) λ§Œμ•½, ν•¨μˆ˜μ˜ Return Type 을 μ •μ˜ν•  λ•Œ label을 λΆ™μ—¬μ£Όλ©΄ λ³„λ„μ˜ label 지정 없이 ν•΄λ‹Ή label 을 μ΄μš©ν•  수 μžˆλ‹€

let intArray: [Int] = [31, 6, 43, 13, 6, 1, 56, 5, 88, 24]

func minMax(array: [Int]) -> (min: Int, max: Int) {
    var currentMin = array[0]
    var currentMax = array[0]
    for value in array[1..<array.count] {
        if value < currentMin {
            currentMin = value
        } else if value > currentMax {
            currentMax = value
        }
    }
    return (currentMin, currentMax)
}
let bounds = minMax(array: intArray)
print("min is \(bounds.min) and max is \(bounds.max)")
min is 1 and max is 88

5. Optional Tuple Return Types

ν•¨μˆ˜κ°€ λ°˜ν™˜ν•˜λŠ” 전체 Tuple 이 nil일 κ°€λŠ₯성이 μžˆλ‹€λ©΄, (Int, Int)? λ˜λŠ” (String, Int, Bool)?κ³Ό 같이 tuple μžμ²΄μ— ?λ₯Ό λΆ™μ—¬ Optiional Tuple Typesλ₯Ό λ°˜ν™˜ν•˜λ„λ‘ ν•  수 μžˆλ‹€.

(Int, Int)?λŠ” Optional Tuple Type이고
(Int?, Int?)λŠ” Optional Int Type을 ν¬ν•¨ν•˜λŠ” Tuple Type이닀.

Optional Tuple Type을 μ‚¬μš©ν•˜λ©΄ 전체 Tuple 뿐 μ•„λ‹ˆλΌ Tuple λ‚΄μ˜ κ°œλ³„ 값도 μžλ™μœΌλ‘œ Optional Type이 λœλ‹€.

let intArray: [Int] = [31, 6, 43, 13, 6, 1, 56, 5, 88, 24]

func minMax(array: [Int]) -> (min: Int, max: Int)? {
    if array.isEmpty { return nil }
    var currentMin = array[0]
    var currentMax = array[0]
    for value in array[1..<array.count] {
        if value < currentMin {
            currentMin = value
        } else if value > currentMax {
            currentMax = value
        }
    }
    return (currentMin, currentMax)
}
if let bounds = minMax(array: []) {
    print("min is \(bounds.min) and max is \(bounds.max)")
} else {
    print("input array is empty.")
}

if let bounds = minMax(array: intArray) {
    print("min is \(bounds.min) and max is \(bounds.max)")
} else {
    print("input array is empty.")
}
input array is empty.
min is 1 and max is 88

6. Function with an Implicit Return

ν•¨μˆ˜μ˜ 전체 본문이 단일 ν‘œν˜„μ‹μΈ 경우 ν•¨μˆ˜λŠ” μ•”μ‹œμ μœΌλ‘œ ν•΄λ‹Ή ν‘œν˜„μ‹μ„ λ°˜ν™˜ν•œλ‹€.

func add(_ num1: Int, _ num2: Int) -> Int {
    num1 + num2
}

print(add(6, 8))    // 14

3. Function Argument Labels and Parameter Names πŸ‘©β€πŸ’»

Swift ν•¨μˆ˜λŠ” argument labelκ³Ό parameter name을 λͺ¨λ‘ κ°–λŠ”λ‹€. argument label 은 ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•  λ•Œ μ‚¬μš©λ˜κ³ , parameter name 은 ν•¨μˆ˜κ°€ 싀행될 λ•Œ λ‚΄λΆ€μ—μ„œ μ‚¬μš©λœλ‹€.

Syntax

func someFunction(argumentLabel parameterName: Int) {
    // In the function body, parameterName refers to the argument value
    // for that parameter.
}

λ§Œμ•½, argument label 을 μƒλž΅ν•˜λ©΄ 기본적으둜 paramter name 을 argument label 둜 μ‚¬μš©ν•˜κ²Œ λœλ‹€.

argument label parameter name
Optional Essential
Used to call a function Used when a function is executed
Non-Unique(Duplicate labels are allowed) Unique

parameter name κ³Ό 달리 argument label 은 non-uniqueμ΄λ―€λ‘œ λ™μΌν•œ 이름을 μ‚¬μš©ν•  수 μžˆμœΌλ‚˜ μ½”λ“œλ₯Ό 읽기 쉽도둝 μ μ ˆν•œ 이름을 μ‚¬μš©ν•˜λŠ” 것이 μ’‹λ‹€.

1. Specifying Argument Labels

argument λ₯Ό default 값인 parameter name κ³Ό λ™μΌν•˜κ²Œ μ‚¬μš©ν•˜μ§€ μ•Šκ³  λ‹€λ₯Έ 이름을 μ‚¬μš©ν•˜λ €λ©΄ parameter name μ•žμ— argument label 을 μž‘μ„±ν•œλ‹€.

func greet(person: String, from hometown: String) -> String {
    return "Hello \(person)!  Glad you could visit from \(hometown)."
}

print(greet(person: "Bill", from: "Cupertino"))
Hello Bill!  Glad you could visit from Cupertino.

2. Omitting Argument Labels

argument label 자체λ₯Ό μƒλž΅ν•˜κΈΈ μ›ν•œλ‹€λ©΄ arguemnt label 에 _ 을 μ‚¬μš©ν•œλ‹€.

func someFunction(_ firstParameterName: Int, secondParameterName: Int) {
    // In the function body, firstParameterName and secondParameterName
    // refer to the argument values for the first and second parameters.
}

someFunction(1, secondParameterName: 2)

4. Special Function Parameters πŸ‘©β€πŸ’»

1. Default Parameter Values

μš°μ„  TypeScript 의 μž‘λ™μ„ 보자.

const add = (num1: number, num2: number = 10): number => +num1 + +num2

console.log(add(5, 20))         // 25
console.log(add(5))             // 15
console.log(add(5, undefined))  // 15
console.log(add(5, NaN))        // NaN


Swift μ—μ„œμ˜ μž‘λ™μ€ λ‹€μŒκ³Ό κ°™λ‹€.

func add(a num1: Int, b num2: Int = 10) -> Int {
    num1 + num2
}

print(add(a: 5, b: 20))     // 25
print(add(a: 5))            // 15


Swift λŠ” Int λŒ€μ‹  nil 을 받을 수 μ—†κΈ° λ•Œλ¬Έμ— 호좜될 λ•Œ num2 argument 없이 호좜된 κ²½μš°μ— λŒ€ν•΄μ„œλ§Œ default value κ°€ μž‘λ™ν•œλ‹€.

print(add(a: 5, b: nil))    // 'nil' is not compatible with expected argument type 'Int'

argument κ°€ μƒλž΅λœ 것이 μ•„λ‹ˆκ³  Int νƒ€μž…μ„ κΈ°λŒ€ν•˜λŠ” 데 nil 이 듀어와 μ—λŸ¬κ°€ λ°œμƒν–ˆλ‹€.


즉, μœ„ TypeScript μ—μ„œ undefined κ°€ λ„˜μ–΄μ˜€λŠ” κ²ƒμ²˜λŸΌ Swift μ—μ„œ nil을 μ²˜λ¦¬ν•˜λ €λ©΄, Optional Parameters λ₯Ό μ‚¬μš©ν•˜κ³ , nil 은 undefined 와 달리 μ΄ˆκΈ°ν™”λŠ” λ˜μ—ˆμœΌλ‚˜ nil μ΄λ―€λ‘œ (μ—„λ°€νžˆ λ§ν•˜λ©΄ μœ„μ—μ„œ TypeScript μ—μ„œλ„ null 을 λ°›μ§€λŠ” λͺ»ν•œλ‹€) argument 둜 nil을 λ„£μ–΄ ν˜ΈμΆœν•˜λ©΄ parameter 에 Optional<Int> νƒ€μž…μ— nil이 μ €μž₯λ˜μ–΄ λ“€μ–΄μ˜΄μœΌλ‘œ default parameter value κ°€ μž‘λ™ν•˜μ§€ μ•Šμ•„ λ‚΄λΆ€μ—μ„œ λ³„λ„λ‘œ μ²˜λ¦¬ν•΄μ•Όν•œλ‹€.

func add(a num1: Int, b num2: Int? = 10) -> Int {
    guard let num2 = num2 else { return num1 + 10 } // 'default parameter value' κ°€ μž‘λ™ν•˜μ§€ μ•ŠλŠ” 것에 λŒ€ν•œ 보정
    return num1 + num2
}

print(add(a: 5, b: 20))     // 25
print(add(a: 5))            // 15

print(add(a: 5, b: nil))    // 15


λ˜ν•œ, default parameter valueλ₯Ό μ‚¬μš©ν•  λ•Œ μ£Όμ˜ν•  것은 Polymorphism(λ‹€ν˜•μ„±)에 μ˜ν•΄ μš°μ„ μˆœμœ„ 상 default parameter valueλŠ” λ¬΄μ‹œλ  수 μžˆλ‹€λŠ” 것이닀.

func add(a num1: Int) -> Int {
    num1 + 100
}

func add(a num1: Int, b num2: Int = 10) -> Int {
    num1 + num2
}

print(add(a: 5, b: 20))     // 25
print(add(a: 5))            // 105

Polymorphism(λ‹€ν˜•μ„±)에 μ˜ν•΄ func add(a num1: Int) -> Int의 호좜이 μš°μ„ μ‹œ 되기 λ•Œλ¬Έμ— func add(a num1: Int, b num2: Int = 10) -> Int의 default valueλ₯Ό μ΄μš©ν•œ ν˜ΈμΆœμ€ μž‘λ™ν•˜μ§€ μ•ŠλŠ”λ‹€.

2. Variadic Parameters

  • Variadic Parameters
func arithmeticMean(_ numbers: Double...) -> Double {
    var total: Double = 0
    for number in numbers {
        total += number
    }
    return total / Double(numbers.count)
}

print(arithmeticMean(2))                    // 2.0
print(arithmeticMean(1, 2, 3, 4, 5))        // 3.0
print(arithmeticMean(3, 8.25, 18.75))       // 10.0


  • Array Parameter
func arithmeticMean(_ numbers: [Double]) -> Double {
    var total: Double = 0
    for number in numbers {
        total += number
    }
    return total / Double(numbers.count)
}

print(arithmeticMean([2]))                  // 2.0
print(arithmeticMean([1, 2, 3, 4, 5]))      // 3.0
print(arithmeticMean([3, 8.25, 18.75]))     // 10.0

Variadic Parameters와 Array Parameter의 λ‚΄λΆ€ μž‘λ™μ€ [Double]둜 κ°™μ§€λ§Œ,
Variadic ParametersλŠ” Double n개λ₯Ό arguments둜 λ°›κ³ ,
Array ParameterλŠ” [Double] 1개λ₯Ό argument둜 λ°›λŠ”λ‹€λŠ” 것이 λ‹€λ₯΄λ‹€.


Swift μ—μ„œ Variadic ParametersλŠ” TypeScript μ—μ„œ Rest Parametersλ₯Ό μ΄μš©ν•΄ λ‹€μŒκ³Ό 같이 κ΅¬ν˜„λ˜λŠ” 것과 κ°™λ‹€.

const arithmeticMean = (...numbers: number[]): number => {
    let total: number = 0
    for (const num of numbers) {
        // @ts-ignore
        total += Number(num)    // total = Number(+total + +num)
    }
    return Number(total) / numbers.length
}

console.log(arithmeticMean(2))                  // 2
console.log(arithmeticMean(1, 2, 3, 4, 5))      // 3
console.log(arithmeticMean(3, 8.25, 18.75))     // 10

3. In-Out Parameters

ν•¨μˆ˜μ˜ parametersλŠ” 기본적으둜 constants μ΄λ―€λ‘œ μˆ˜μ •ν•  수 μ—†λ‹€.

λ§Œμ•½, parametersλ₯Ό μˆ˜μ •ν•˜κ³ , ν•¨μˆ˜κ°€ μ’…λ£Œλœ 후에도, 즉, ν•¨μˆ˜ scope λ°–μ—μ„œλ„ 이 값을 μœ μ§€ν•˜κ³  μ‹Άλ‹€λ©΄ parameter type μ•žμ— inout ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•΄ In-Out Parameters둜 λ§Œλ“€ 수 μžˆλ‹€.

In-Out ParametersλŠ” variables만 arguments둜 받을 수 μžˆλ‹€. constantsλ‚˜ literalsλŠ” μˆ˜μ •μ΄ λΆˆκ°€ν•˜λ―€λ‘œ μž…λ ₯ 받을 수 μ—†λ‹€.

func swapTwoInts(_ a: inout Int, _ b: inout Int) {
    let temporaryA = a
    a = b
    b = temporaryA
}
var someInt = 3
var anotherInt = 107
swapTwoInts(&someInt, &anotherInt)

print("someInt is now \(someInt), and anotherInt is now \(anotherInt)")
someInt is now 107, and anotherInt is now 3


In-Out Parametersλ₯Ό μ •λ¦¬ν•˜λ©΄ λ‹€μŒκ³Ό κ°™λ‹€.

  • In-Out Parameters λŠ” parameter type μ•žμ— inout ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•΄ λ§Œλ“ λ‹€.
  • In-Out Parameters λ₯Ό μ‚¬μš©ν•œ ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•  λ•Œ arguments μ•žμ— & ν‚€μ›Œλ“œλ₯Ό λΆ™μ—¬ ν˜ΈμΆœν•œλ‹€.

μž‘λ™ μˆœμ„œλŠ” λ‹€μŒκ³Ό κ°™λ‹€.

  1. ν•¨μˆ˜κ°€ 호좜될 λ•Œ arguments의 값이 parameters 에 λ³΅μ‚¬λœλ‹€.
  2. λ³΅μ‚¬λœ arguments 의 값이 ν•¨μˆ˜μ˜ bodyμ—μ„œ μˆ˜μ •λœλ‹€.
  3. ν•¨μˆ˜κ°€ μ’…λ£Œλ  λ•Œ arguments의 Pointer λ₯Ό μ΄μš©ν•΄ 값을 μˆ˜μ •ν•œλ‹€.

5. Function Types πŸ‘©β€πŸ’»

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

μœ„ 두 ν•¨μˆ˜μ˜ Function Types λŠ” λ‹€μŒκ³Ό κ°™λ‹€. (Int, Int) -> Int


func printHelloWorld() {
    print("hello, world")
}

μœ„ ν•¨μˆ˜μ˜ Function Types λŠ” λ‹€μŒκ³Ό κ°™λ‹€. () -> Void

1. Using Function Types

Swift μ—μ„œλŠ” Function Types μ—­μ‹œ λ‹€λ₯Έ Types와 같이 μ‚¬μš©ν•  수 μžˆλ‹€.

1 ) Function Declarations

func addTwoInts(_ a: Int, _ b: Int) -> Int {
    a + b
}
func multiplyTwoInts(_ a: Int, _ b: Int) -> Int {
    a * b
}
var mathFunction: (Int, Int) -> Int

mathFunction = addTwoInts(_:_:)
print(mathFunction(5, 7))   // 12

mathFunction = multiplyTwoInts(_:_:)
print(mathFunction(5, 7))   // 35


2 ) Function Expressions

λ‹€μŒ μ˜ˆμ œλŠ” Function Typesλ₯Ό μ΄μš©ν•΄ λ³€μˆ˜λ‚˜ μƒμˆ˜μ˜ νƒ€μž…μ„ μ§€μ •ν•˜κ³ , Closuresλ₯Ό ν• λ‹Ήν•΄ ν•¨μˆ˜λ₯Ό μ„ μ–Έν•œλ‹€.
이것은 μœ„ Function Declarations와 λ™μΌν•œ κ²°κ³Όλ₯Ό κ°–λŠ”λ‹€.
(이 경우 TDZ 둜 μΈν•œ Hoistingκ°œλ…λ„ λ™μΌν•˜κ²Œ μ μš©λœλ‹€.)

// With Function Types
let addTwoInts: (Int, Int) -> Int = { (a: Int, b: Int) in
    a + b
}

// Without Function Types
let multiplyTwoInts = { (a: Int, b: Int) in
    a * b
}
print(addTwoInts(5, 7))         // 12
print(multiplyTwoInts(5, 7))    // 35


μœ„ μ½”λ“œ μ—­μ‹œ TypeScript 와 λΉ„κ΅ν•΄λ³΄μž

// With Function Types
const addTwoInts: (num1: number, num2: number) => number
    = (a, b) => a + b

// Without Function Types
const multiplyTwoInts = (a: number, b: number): number => a * b
console.log(addTwoInts(5, 7))           // 12
console.log((multiplyTwoInts(5, 7)))    // 35


3 ) Define Function Types from Type Alias

Protocolsλ₯Ό μ΄μš©ν•΄ Classes, Structures λ“±κ³Ό 같은 νƒ€μž…μ— Blueprintλ₯Ό μ œκ³΅ν•˜λ“― ν•¨μˆ˜ μ—­μ‹œ typealiasλ₯Ό μ΄μš©ν•΄ Type을 κ°•μ œν•  수 μžˆλ‹€.

typealias ArithmeticCalc = (Int, Int) -> Int

let addTwoInts: arithmeticCalc = { $0 + $1 }
let multiplyTwoInts: arithmeticCalc = { $0 * $1 }
print(addTwoInts(5, 7))         // 12
print(multiplyTwoInts(5, 7))    // 35


μœ„ μ½”λ“œ μ—­μ‹œ TypeScript 와 λΉ„κ΅ν•΄λ³΄μž

type GenericFunc = <Number>(a: number, b: number) => number

const addTwoInts: GenericFunc = (a, b) => a + b
const multiplyTwoInts: GenericFunc = (a, b) => a * b

λ˜λŠ”

type GenericType<Number> = (a: number, b: number) => number

const addTwoInts: GenericType<Number> = (a, b) => a + b
const multiplyTwoInts: GenericType<Number> = (a, b) => a * b

λ¬Όλ‘  μƒλž΅λ„ κ°€λŠ₯ν•˜λ‹€.

type GenericFunc = (a: number, b: number) => number

const addTwoInts: GenericFunc = (a, b) => a + b
const multiplyTwoInts: GenericFunc = (a, b) => a * b
console.log(addTwoInts(5, 7))           // 12
console.log((multiplyTwoInts(5, 7)))    // 35

2. Function Types as Parameter Types

Swift 의 ν•¨μˆ˜λŠ” First-Class Citizenμ΄λ―€λ‘œ parameters κ°€ 될 수 μžˆλ‹€.

let addTwoInts: (Int, Int) -> Int = { (a: Int, b: Int) in
    a + b
}

let multiplyTwoInts = { (a: Int, b: Int) in
    a * b
}
func printMathResult(mathFunction function: (Int, Int) -> Int, _ a: Int, _ b: Int) {
    print("Result: \(function(a, b))")
}

printMathResult(mathFunction: addTwoInts, 5, 7)       // Result: 12
printMathResult(mathFunction: multiplyTwoInts, 5, 7)  // Result: 35

printMathResult(mathFunction:_:_:)의 첫 번째 parameter λŠ” (Int, Int) -> Int νƒ€μž…μ˜ ν•¨μˆ˜λ₯Ό argument둜 λ°›λŠ”λ‹€.


μœ„ μ½”λ“œ μ—­μ‹œ TypeScript 와 λΉ„κ΅ν•΄λ³΄μž

const addTwoInts: (num1: number, num2: number) => number
    = (a, b) => a + b

const multiplyTwoInts = (a: number, b: number) => a * b
// const printMathResult = (mathFunction: Function, a: number, b: number) => console.log(`Result: ${mathFunction(a, b)}`)
const printMathResult = (mathFunction: (num1: number, num2:number) => number, a: number, b: number) => {
    console.log(`Result: ${mathFunction(a, b)}`)
}

printMathResult(addTwoInts, 5, 7)       // Result: 12
printMathResult(multiplyTwoInts, 5, 7)  // Result: 35

3. Function Types as Return Types

λ§ˆμ°¬κ°€μ§€λ‘œ Swift 의 ν•¨μˆ˜λŠ” First-Class Citizenμ΄λ―€λ‘œ return type 이 될 수 μžˆλ‹€.

0보닀 크면 stepBackward(_:) ν•¨μˆ˜λ₯Ό μ‹€ν–‰ν•˜κ³ , 0보닀 μž‘μœΌλ©΄ stepForward(_:) ν•¨μˆ˜λ₯Ό μ‹€ν–‰ν•΄ 0에 λ„λ‹¬ν•˜λŠ” λ‘œμ§μ„ 좜λ ₯ν•΄λ³΄μž.

func stepForward(_ input: Int) -> Int {
    print(#function)
    return input + 1
}
func stepBackward(_ input: Int) -> Int {
    print(#function)
    return input - 1
}
func chooseStepFunction(backward: Bool) -> (Int) -> Int {
    backward ? stepBackward(_:) : stepForward(_:)
}

chooseStepFunction(backward:) ν•¨μˆ˜λŠ” (Int) -> Int ν•¨μˆ˜λ₯Ό return ν•œλ‹€.


func movingStart(initialValue: Int) {
    var currentValue = initialValue
    let moveNearToZero = chooseStepFunction(backward: currentValue > 0)

    print("Counting to zero:")
    while currentValue != 0 {
        print("\(currentValue)... Call ", terminator: "")
        currentValue = moveNearToZero(currentValue)
    }
    print("zero!\n")
}

movingStart(initialValue: 4)
movingStart(initialValue: -3)
Counting to zero:
4... Call stepBackward(_:)
3... Call stepBackward(_:)
2... Call stepBackward(_:)
1... Call stepBackward(_:)
zero!

Conting to zero:
-3... Call stepForward(_:)
-2... Call stepForward(_:)
-1... Call stepForward(_:)
zero!


μœ„ μ½”λ“œ μ—­μ‹œ TypeScript 와 λΉ„κ΅ν•΄λ³΄μž

const stepForward = (input: number): number => input + 1
const stepBackward = (input: number): number => input - 1
const chooseStepFunction = (backward: boolean): (input: number) => number => {
    return backward ? stepBackward : stepForward
}
const movingStart = (initialValue: number) => {
    let currentValue = initialValue
    const moveNearToZero = chooseStepFunction(initialValue > 0)

    console.log("Counting to zero:")
    while (currentValue !== 0) {
        console.log(`${currentValue}... Call ${moveNearToZero.name}`)
        currentValue = moveNearToZero(currentValue)
    }
    console.log("zero!\n")
}

movingStart(4)
movingStart(-3)
Counting to zero:
4... Call stepBackward
3... Call stepBackward
2... Call stepBackward
1... Call stepBackward
zero!

Counting to zero:
-3... Call stepForward
-2... Call stepForward
-1... Call stepForward
zero!

6. Nested Functions πŸ‘©β€πŸ’»

μœ„μ—μ„œ μž‘μ„±λœ ν•¨μˆ˜λŠ” λͺ¨λ‘ Global Scope의 접근성을 κ°–λŠ” Global Functionsλ‹€.
ν•˜μ§€λ§Œ ν•¨μˆ˜μ˜ body μ•ˆμ— λ‹€λ₯Έ ν•¨μˆ˜λ₯Ό μ •μ˜ν•  수 μžˆλŠ”λ° 이λ₯Ό Nested Functions라 ν•œλ‹€.


μœ„ Function Types as Return Types λ₯Ό Nested Functions둜 λ°”κΏ”λ³Έλ‹€.

func chooseStepFunction(backward: Bool) -> (Int) -> Int {
    func stepForward(_ input: Int) -> Int {
        print(#function)
        return input + 1
    }
    func stepBackward(_ input: Int) -> Int {
        print(#function)
        return input - 1
    }
    
    return backward ? stepBackward(_:) : stepForward(_:)
}

chooseStepFunction(backward:) ν•¨μˆ˜λ₯Ό μœ„ν•΄ μ‚¬μš©λ˜λŠ” stepForward(_:), stepBackward(_:) ν•¨μˆ˜λ₯Ό chooseStepFunction(backward:) ν•¨μˆ˜μ˜ body에 쀑첩해 접근을 μ œν•œν•˜κ³  가독성읖 λ†’μ˜€λ‹€.

func movingStart(initialValue: Int) {
    var currentValue = initialValue
    let moveNearToZero = chooseStepFunction(backward: currentValue > 0)
    
    print("Counting to zero:")
    while currentValue != 0 {
        print("\(currentValue)... Call ", terminator: "")
        currentValue = moveNearToZero(currentValue)
    }
    print("zero!\n")
}

movingStart(initialValue: 4)
movingStart(initialValue: -3)
Conting to zero:
4... Call stepBackward(_:)
3... Call stepBackward(_:)
2... Call stepBackward(_:)
1... Call stepBackward(_:)
zero!

Conting to zero:
-3... Call stepForward(_:)
-2... Call stepForward(_:)
-1... Call stepForward(_:)
zero!


μœ„ μ½”λ“œ μ—­μ‹œ TypeScript 와 λΉ„κ΅ν•΄λ³΄μž

const chooseStepFunction = (backward: boolean): (input: number) => number => {
    const stepForward = (input: number): number => input + 1
    const stepBackward = (input: number): number => input - 1

    return backward ? stepBackward : stepForward
}
const movingStart = (initialValue: number) => {
    let currentValue = initialValue
    const moveNearToZero = chooseStepFunction(initialValue > 0)

    console.log("Counting to zero:")
    while (currentValue !== 0) {
        console.log(`${currentValue}... Call ${moveNearToZero.name}`)
        currentValue = moveNearToZero(currentValue)
    }
    console.log("zero!\n")
}

movingStart(4)
movingStart(-3)
Counting to zero:
4... Call stepBackward
3... Call stepBackward
2... Call stepBackward
1... Call stepBackward
zero!

Counting to zero:
-3... Call stepForward
-2... Call stepForward
-1... Call stepForward
zero!

Nested Functionsλ₯Ό ν™œμš©ν•˜λ©΄ μ „μ—­μ—μ„œ μ ‘κ·Όν•  ν•„μš”κ°€ μ—†λŠ” ν•¨μˆ˜μ˜ scopeλ₯Ό μ œν•œν•΄ μ½”λ“œλ₯Ό λ”μš± μ•ˆμ „ν•˜κ³  가독성 λ†’κ²Œ λ§Œλ“€ 수 μžˆλ‹€.
단, Swift μ—μ„œλŠ” μœ„ TypeScript μ—μ„œμ™€ 달리 μ€‘μ²©λœ ν•¨μˆ˜λ₯Ό let λ˜λŠ” var둜 μ •μ˜ν•  수 μ—†λ‹€. λ°˜λ“œμ‹œ func ν‚€μ›Œλ“œλ₯Ό μ΄μš©ν•΄ μ •μ˜ν•΄μ•Όν•œλ‹€ (cf. Closure Expressions λ₯Ό μ°Έκ³ ν•œλ‹€).




Reference

  1. β€œFunctions.” The Swift Programming Language Swift 5.7. accessed Oct. 19, 2022, Swift Docs Chapter 5 - Functions.
  2. β€œFirst-class citizen.” Wikipedia. Oct. 15, 2022, Wikipedia - First Class Citizen.
  3. β€œFirst-class function.” Wikipedia. Jul. 14, 2022, Wikipedia - First Class Function.
  4. β€œSpread syntax.” MDN Web Docs. Sep. 19, 2022, MDN - Spread Syntax(…).
  5. β€œRest parameters.” MDN Web Docs. Sep. 19, 2022, MDN - Rest Parameters(…args).