안녕하세요! 오늘은 Swift 함수 포스팅을 작성하려고 합니다.
기존에 작성한 함수 편에서 조금 내용을 추가해서 포스팅 작성해보겠습니다.
함수는 어떤 기능을 하는 코드의 모음이며, 입력과 출력이 있을 수 있습니다.
함수를 실행하기 위해서는 2가지 과정을 거칩니다. 바로 선언, 호출(실행)입니다. 따라서 함수를 선언만 한다면 호출하여 자주 사용기에도 편리합니다.
func thisFunction() {
print("함수 선언입니다.")
}
thisFunction() // 함수 호출
이처럼 반복되는 동작을 함수로 만들면 재사용이 가능하고 코드를 단순화시킬 수 있습니다. 직접 개발자가 함수를 만들 수도 있지만 이미 애플에서 제공하는 함수들도 있습니다. 대표적으로 print()가 있죠!
지금까지 함수 정의 및 역할에 대해서 알아보았습니다. 이제 더 자세히 보도록 하겠습니다!
함수 안에 함수를 작성할 수도 있습니다. 함수를 제한적으로 사용하고 싶을 때 사용됩니다. 하지만 함수(a) 안에 선언된 함수(b)는 함수(a) 안에서만 사용할 수 있습니다.
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)
매개변수(parameter)는 함수 안에서의 정의 및 사용에 나열되어 있는 변수들을 의미합니다.
전달 인자(argument)는 함수를 호출할 때 전달되는 실제 값을 의미합니다.
실제 예시를 들어보겠습니다!
func myFunction(number1 a: Int, number2 b: Int)-> Int {
return a + b
}
myFunction(number1: 2, number2: 4)
argument label은 parameter를 외부에서 볼 때, 함수 호출시 사용하는 이름이라고 했습니다. 그렇다면 number1, number2가 해당되겠죠.
func myFunction(number1: Int, number2: Int) -> Int{
return number 1 + number2
}
myFunction(number1: 2, number2: 4)
위 경우는 argument label과 parameter name이 동일한 이름을 가진 경우입니다.
argument label을 생략할 수도 있습니다. 생략하는 경우를 wildcard pattern이라고 합니다.
아규먼트 레이블을 생략하려면 under bar를 추가하면 됩니다. 아래처럼요!
func plusFunction(_ number1: Int, _ number2: Int) -> Int {
return number 1 + number2
}
plusFunction(2, 3)
함수를 사용할 때, 입력으로 받는 파라미터 값의 개수가 정해지지 않을 때 개수에 맞게 여러 함수를 선언해야한다면 많이 불편할 것 같지 않나요?
이렇게 정해지지 않은 여러 파라미터를 받아야 할 때 가변 파라미터를 적용하면 됩니다.
func plusFunction(numbers: Int…, num: Int = 5) -> Int {}
함수내의 파라미터는 기본적으로 값타입이고(복사되어서 전달) 임시상수이기 때문에 변경 불가합니다. 함수 내에서 값을 변경하고 싶으면 함수 내에서 따로 선언하여 사용해야 합니다.
var num1 = 123 // 전역변수
var num2 = 456 // 전역변수
func swap(a: Int, b: Int) {
var c = a
a = b
b = c
}
swap(a: num1, b: num2)
만약 파라미터 값을 함수 내부에서 변경하고 변경 값을 반영하고 싶다면 함수 선언문에 inout을 사용하면 됩니다.
참조로 전달하여 함수 내에서 변수를 직접 수정하도록 돕습니다.
num1 = 123
num2 = 456
func swapNumbers(a: inout Int, b: inout Int) {
var temp = a
a = b
b = temp
}
swapNumbers(a: &num1, b: &num2)
print(num1)
print(num2)
inout 파라미터 사용시 주의점
1) 상수(let)나, 리터럴 전달하는 것 불가능
2) 파라미터의 기본값 선언을 허용하지 않음
3) 가변파라미터(여러개의 파라미터)로 선언하는 것 불가능
애플 개발자 문서에 함수 지칭시 사용 되기 때문에 함수를 어떻게 읽어야 하는지 배울 필요가 있습니다.
문법적으로 함수에 대해서 개발자들끼리 이야기할 때, 함수를 이름을 말하는 경우 argument label 까지 말해야 합니다. (아래같이)
doSomething()
numberPrint(n:)
chooseStepFunction(backward:value:)
addPrintFunction(_: _:)
함수 타입을 나타날 때는 parameter의 type과 리턴 타입을 포함하여 표시합니다.
( ) -> ( ) // 파라미터도 리턴도 없는 함수
( ) -> Void // ()를 void라고 표기할 수 있습니다.
(String) -> String // String 값을 입력으로 받고 String을 리턴
(Int, Int) -> Void // Int 값 2개를 입력으로 받고 리턴 값이 없는 함수
리턴 값을 가지고 있는 함수의 리턴값을 사용하지 않을 때 사용하는 attribute keyword입니다. (attribute keyword는 선언이나 타입에 대한 추가적인 정보를 컴파일러에게 알려주는 역할 수행)
리턴값을 가지고 있는 함수의 리턴값을 사용하지 않을 때 결과값을 사용하지 않는다는 경고 내용이 나옵니다. 이 경고를 방지할 수 있습니다.
_ = doSomething() // wildcard pattern을 활용하는 방법
@discardableResult
func doSomething( ) -> String {
….
return “Swift”
}
스위프트는 overloading을 지원하는 언어입니다. overload는 '과적하다'라는 의미로 하나의 함수 이름에 여러 함수를 과적하는 것입니다.
오버로딩의 정의는 한 클래스 내에 이미 사용하려는 이름과 같은 이름을 가진 메소드가 있더라도 매개변수의 개수 또는 타입이 다르면, 같은 이름을 사용해서 메소드를 정의할 수 있습니다.
내부적으로 컴파일러가 오버로딩된 함수를 함수이름, 파라미터 수/ 자료형, 아규먼트 레이블, 리턴형 모두 포함해서 함수 식별합니다. 따라서 함수 이름이 같더라도 오버로딩된 함수를 식별할 수 있습니다.
오버로딩 예시 - 애플에서 정의된 print 함수
print(<#T##items: Any...##Any#>, to: &<#T##TextOutputStream#>)
print(<#T##items: Any...##Any#>, separator: <#T##String#>, terminator: <#T##String#>)
print(<#T##items: Any...##Any#>, separator: <#T##String#>, terminator: <#T##String#>, to: &<#T##TextOutputStream#>)