함수의 파라미터는 아규먼트 라벨(argument label)과 파라미터 이름(parameter name)이 있다. 전자는 함수를 호출할 때, 후자는 함수를 사용할 때 사용한다. 일반적으로 파라미터는 파라미터 이름을 아규먼트 라벨로 사용한다.
모든 파라미터는 유니크한 이름이 있다. 여러 개의 파라미터의 아규먼트 라벨이 같을 수는 있지만, 유니크한 라벨을 사용하는 게 보다 가독성이 뛰어나다.
아규먼트 라벨을 파라미터 이름 전에 쓴다.
func func_example(argumentLabel parameterName: Int) {
// Int the function body, parameterNmae refers to the argument value
// for that parameter
}
func greet(person: String, from hometown: String) -> String {
return "Hello \(person)! Glad you could visit from \(hometown)."
}
print(greet(person: "Bill", from: "LA"))
// Hello Bill! Glad you could visit from LA.
from hometown
의 from
과 hometown
이 각각 아규먼트 라벨과 파라미터 이름이다.
아규먼트 라벨을 통해 보다 가독성 있는 방식으로 코드를 작성할 수 있다.
파라미터로 아규먼트 라벨을 사용하고 싶지 않을 때에는 언더스코어 _
를 사용하면 된다.
func func_example(_ fistParameterName: Int, secondParameterName: Int){
// In the function body, firstParameterName and secondParameterName
// refers to the argument values for the first and second parameters.
}
func_example(1, secondParameterName:2)
파라미터 타입을 선언한 뒤 파라미터에 값을 할당하는 방법으로 디폴트 값을 설정할 수 있다. 디폴트 값이 있다면 함수를 선언할 때 이 파라미터에 값을 생략할 수도 있다.
func func_example(parameterWithoutDefault: Int, parameterWithDefault: Int = 12){
// If you omit the second argument when calling this function, then
// the value of parameterWithDefault is 12 inside the function body.
}
func_example(parameterWithoutDefault: 3, parameterWithDefault: 6)
// each value: 3, 6
func_example(parameterWithoutDefault: 3)
// each value: 3, 12
함수가 맡은 주요 기능이 필요한 파라미터가 아니라면 디폴트 값을 설정해 편리해도 사용하자.
특정 타입의 데이터를 하나 이상 받아들일 수 있다. 파라미터에 입력되는 개수가 정확히 몇 개인지 사전에 정할 수 없을 때 ...
라고 써서 가변 파라미터임을 표현할 수 있다.
받아들이는 데이터 타입이 정해졌다면 이 배열을 넘겨받는다고 이해할 수 있다.
가령 주어진 배열의 평균을 계산하는 계산기 함수를 선언한다고 하자.
func Calc(_ numbers: Double...) -> Double {
var total: Double = 0
for number in numbers{
total += number
}
return total / Double(numbers.count)
}
Calc(1, 2, 3, 4, 5)
// 3.0 returned
함수 파라미터는 상수가 기본값이다. 파라미터로 입력받은 데이터를 바꾸는 건 런타임 에러를 발생시킨다. 그렇다면 입력받은 파라미터 값을 바꾸고, 함수 호출이 끝난 뒤에도 데이터를 바꾼 채로 유지하고 싶다면 어떻게 해야할까? 그런 파라미터를 인-아웃 파라미터로 정의하면 된다.
파라미터 타입 바로 전에 인아웃 inout
이라는 키워드를 작성하자. 입력받은 파라미터 값이 함수 내에서 바뀐다면, 호출이 끝난 뒤 원본을 대체할 것이다. 함수를 호출할 때 원본 데이터 변수 앞에 and 연산자 &
기호를 사용하자.
func swap(_ a: inout Int, _ b: inout Int) {
let tempA = a
a = b
b = tempA
}
var a = 10
var b = 20
swap(&a, &b)
// a: 20, b: 10 swapped
swap
함수가 리턴을 사용하지 않지만 인-아웃 파라미터를 통해 함수 내부에서 바깥 변수를 조정하고 있다.
함수에는 파라미터로 입력되는 데이터 타입, 리턴하는 데이터 타입이 있다.
func add(_ a: Int, _ b: Int) -> Int {
return a + b
}
func Hello(){
print("Hello, World!")
}
add
함수는 정수 파라미터 두 개를 입력값으로 받아들여 정수를 리턴하고, Hello
함수는 파라미터 없이 사용되며 리턴도 하지 않는다. 이 없다는 게 void
임을 기억하자.
변수나 상수를 함수 타입으로 선언해 할당할 수 있다.
var mathFunction: (Int, Int) -> Int = add
mathFunction
이라는 변수는 두 개의 정수 값을 받아들여 정수를 리턴하며, 이 변수가 add
라는 함수를 참조하도록 설정한다는 코드다.
스위프트 타입 체커라 불리는 이 할당 방식을 통해 우변의 함수가 좌변의 변수와 같은 타입인지 확인할 수 있다.
print("Result: \(mathFunction(2, 3))")
// Result: 5
타입 추론을 통해서도 사용 가능하다.
let anotherMathFunction = add
// anotherMathFunction: (Int, Int) -> Int
(Int, Int) -> Int
와 같은 함수 타입을 다른 함수에 사용할 파라미터로도 사용할 수 있다.
func printMathResult(_ mathFunction: (Int, Int) -> Int, _ a: Int, _ b: Int){
print("Result: \(mathFunction(a, b))")
}
printMathResult(add, 1, 4)
// Result: 5
printMathResult
함수는 세 개의 파라미터를 가지고, 이 중 첫 번째 파라미터인 mathFunction
이 앞서 설명한 함수 타입임을 확인하자. 에러가 나지 않도록 타입 매칭이 되도록 확인하자.
함수 타입을 다른 함수의 리턴 타입으로도 쓸 수 있다. 리턴 타입 연산자 ->
다음에 매칭될 함수 타입을 작성하자.
func stepForward(_ input: Int) -> Int {
return input + 1
}
func stepBackward(_ input: Int) -> Int {
return input - 1
}
func chooseStepFunction(backward: Bool) -> (Int) -> Int {
return backward ? stepBackward : stepForward
}
var currentValue = 3
let moveNearerToZero = chooseStepFunction(backward: currentValue > 0)
stepForward
와 stepBackward
함수의 리턴 타입이 모두 (Int) -> Int
임을 확인하자.
currentValue
가 0보다 크기 때문에 0으로 이동하기 위해 두 개 함수 중 어떤 함수를 호출할지 택할 수 있다.
print("Counting to zero: ")
while currentValue != 0 {
print("\(currentValue)...")
currentValue = moveNearerToZero(currentValue)
}
print("zero!")
// Counting to zero:
// 3...
// 2...
// 1...
// zero!
함수 안에 함수를 중첩해서(nested) 사용할 수도 있다.
중첩 함수는 기본적으로 함수 바깥에서는 숨겨져 있다. 중첩된 함수를 감싼(enclosing) 함수를 통해 접근, 사용하자.
func chooseStepFunction(backward: Bool) -> (Int) -> Int {
func stepForward(input: Int) -> Int {return input + 1}
func stepBackward(input : Int) -> Int {return input -1}
return backward ? stepBackward : stepForward
}
var currentValue = -4
let moveNearerToZero = chooseStepFunction(backward: currentValue > 0)
// moveNearerToZero now refers to the nested stepForward() function
while currentValue != 0 {
print("\(currentValue)... ")
currentValue = moveNearerToZero(currentValue)
}
print("zero!")
// -4...
// -3...
// -2...
// -1...
// zero!