Swift 함수
함수와 메서드
함수와 메서드는 기본적으로 같다 상황이나 용도에 따라 다른 용어로 부른다
메서드: 구조체, 클래스, 열거형 등 특정 타입에 연관되어 사용하는 함수
함수: 모듈 전체에서 전역적으로 사용 가능한 함수
함수는 조건문이나 반복 문과 달리 소괄호()를 생략 불가능
재정의(오버라이드), 중복 정의(오버로드)를 모두 지원
따라서 매개변수 타입이 다르면 같은 이름의 함수를 여러 개 만들 수 있고 매개변수의 개수가 달라도 같은 이름의 함수를 만들 수 있다 -> 매개변수가 다르면 다른 함수다
함수의 정의와 호출
함수의 이름, 매개변수, 반환 타입 등을 사용하여 함수를 정의한다
1
2
3
4
func 함수이름 (매개변수...) -> 반환 타입 {
실행구문
return 반환 값
}
return 생략 조건
만약 결괏값이 반환 타입과 같다면 return 없이 그 결괏값이 함수의 반환값이 된다
매개변수
매개변수 없음 공백으로 표현
1
2
3
func function () -> String {
실행구문
}
매개변수 여러 개
1
2
3
4
5
6
func function (a: Int, b: Int, c: String) -> String {
return "Hello to day is \(a)M \(b)d \(c). "
}
print(function(a:12, b:13, c:"Monday")) //Hello to day is 12M 13d Monday.
매개변수 이름과 전달인자 레이블
바로 위 function 함수에서 매개변수 이름과 전달인자 레이블은 모두 a, b, c이다
매개변수 이름만 작성하면 매개변수 이름 == 전달인자 레이블 이렇게 된다
구분하려면 매개변수 이름 앞에 전달인자 레이블을 작성한다
1
2
3
4
5
func function1 (from name: String, to reciver: String) -> String {
name + " " + "hello" + " " + reciver
}
print(function1(from:"min", to:"jony")) //min hello jony
function1에서 매개변수의 이름 name, reciver이고 전달인자 레이블 from, to이다
매개변수 이름은 함수 내부에서만 사용하고 전달인자 레이블은 함수 외부에서 사용한다
두 개를 같은 이름으로 사용해도 되지만 다른 이름으로 사용하는 것은 함수 외부에서 매개변수의 역할을 더 명확히 하기 위해서이
다
만약 전달인자 레이블은 사용하고 싶지 않으면 와일드카드 식별자(_) 사용
1
2
3
4
5
func function2 (_ a: Int, _ b: Int) -> Int {
return a + b
}
print(function2(1,2)) //3
전달인자의 이름만 바뀌면 함수의 이름이 바뀌므로 함수 중복 정의로 동작할 수 있다
가변 매개변수
가변 매개변수는 매개변수의 개수가 정해지지 않을 때 사용할 수 있다
입력될 값의 개수가 0개 이상인 경우 사용 가능하다
String…으로 표현 데이터 타입 뒤에 … 을 붙인다
1
2
3
4
5
6
7
8
9
10
11
12
func function (friends names: String...) -> String {
var friendsNames: String = ""
for friend in names {
friendsNames += "Hello \(friend)! "
}
return friendsNames
}
print(function(friends: "min","nick","jenny"))//Hello min! Hello nick! Hello jenny!
가변 매개변수는 함수마다 하나만 가질 수 있다
입출력 매개변수
함수의 전달인자로 값을 전달할 때 보통 값을 복사해서 전달한다 만약 값이 아닌 참조로 전달하려면 입출력 매개변수를 사용한다 값을 전달하기보다는 그 값의 주소를 전달하는 느낌 포인터 비슷
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var numbers: [Int] = [1,2,3]
func noReference(_ arr: [Int]) {
var copyArr: [Int] = arr
copyArr[1] = 1 //복사본을 변경한것
}
func reference(_ arr:inout [Int]) {
arr[1] = 1 //참조를 통해서 배열의 [1]인덱스 값을 1로 바꿈
}
noReference(numbers)
print(number[1]) //2 원래의 배열은 바뀌지 않고 복사본만 바뀜
reference(&numbers)
print(number[1]) //1 //배열의 값이 바귀어 출력된다
참조를 이용하려면 매개변수 데이터 타입 앞에 inout을 붙이고 매개변수에 값을 넣을 때 &를 이용해야 참조 가능
반환이 없는 함수
없음을 표시 Void로 표기하거나 아예 반환 타입 표현을 생략한다
1
2
3
4
5
6
7
8
9
10
func function1() {
print("Hello")
}
func function2(_ name: String) -> Void {
print("my name is \(name)!")
}
function1
function2("kkka") //my name is kkka!
데이터 타입으로서의 함수
함수는 하나의 데이터 타입으로 사용 가능하다
매개변수 타입과 반환 타입으로 구성된 하나의 타입으로 정의할 수 있다
1
2
3
4
5
(매개변수 타입 나열) -> 반환 타입
func say(name: String) -> String {
...
}
위에 say 함수의 타입은 (String) -> String이 된다
만약 매개변수와 반환값이 모두 없으면
- (Void) -> Void
- () -> Void
- () -> ()
함수 타입 사용
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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: CalculateTwoInts = addTwoInts //데이터 타입이 같다
print(mathFunction(2,5)) //7
mathFunction = multiplyTwoInts //데이터 타입이 같다
print(mathFunction(2,5)) //10
위에서 CalculateTwoInts라는 데이터 타입을 만들고 이 데이터 타입은 함수 addTwoInts과 multiplyTwoInts 데이터 타입과 같아서 mathFunction = multiplyTwoInts 이 표현이 가능하다
mathFunction = multiplyTwoInts을 사용하면 multiplyTwoInts의 함수를 mathFunction 이름으로 사용 가능하다고 생각하면 된다
전달인자로 함수를 전달받는 함수
1
2
3
4
5
6
7
8
9
10
11
typealias CalculateTwoInts = (Int,Int) -> Int
func addTwoInts(_ a: Int, _ b: Int) -> Int {
return a + b
}
func result(_ mathFunction: CalculateTwoInts, _ a: Int, _ b: Int) {
print("Result: \(mathFunction(a,b)) ")
} // 매개변수 데이터 타입 CalculateTwoInts로 함수를 받는다
result(addTwoInts,3,5) //Result: 8
함수 addTwoInts를 전달인자로 받아 이용한 코드
중첩 함수
함수를 중첩해서 함수안에 함수를 구현하는 방법이다 중첩 함수는 함수의 사용 범위를 제한할 수 있다
함수안에 함수
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
typealias MoveFunc = (Int) -> Int
func goRight(_ currentPosition: Int) -> Int {
print("go right")
return currentPosition + 1
}
func goLeft(_ currentPosition: Int) -> Int {
print("go left")
return currentPosition - 1
}
func functionForMove(_ shouldGoLeft: Bool) -> MoveFunc {
return shouldGoLeft ? goLeft : goRight
}
var position: Int = 3
let moveToZero: MoveFunc = functionForMove(position > 0)
print("go to zero")
while position != 0 {
print("\(position)")
position = moveToZero(position)
}
print("0")
//go to zero
//3
//go left
//2
//go left
//1
//go left
//0
중복 함수 사용
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
typealias MoveFunc = (Int) -> Int
func functionForMove(_ shouldGoLeft: Bool) -> MoveFunc {
func goRight(_ currentPosition: Int) -> Int {
print("go right")
return currentPosition + 1
}
func goLeft(_ currentPosition: Int) -> Int {
print("go left")
return currentPosition - 1
}
return shouldGoLeft ? goLeft : goRight
}
var position: Int = -4
let moveToZero: MoveFunc = functionForMove(position > 0)
print("go to zero")
while position != 0 {
print("\(position)")
position = moveToZero(position)
}
print("0")
//go to zero
//-4
//go right
//-3
//go right
//-2
//go right
//-1
//go right
//0
위 두개의 방법은 별차이 없지만 코드가 복잡해지면 전역함수가 많은것보다는 두번째 방법처럼 중복함수를 사용하여 함수의 사용 범위를 조금 더 명확히 표현 가능하다
반환값을 무시할 수 있는 함수
함수를 작성하다 보면 함수 내부에서 필요한 작업이 끝나 반환값이 필요 없는 경우가 있다 이경우 그냥 실행하면 경고를 내보내지만 @discardableResult 선언 속성을 사용하면 된다
1
2
3
4
5
6
7
8
9
10
11
func addFunction(_ a: Int, _ b: Int) -> Int { //리턴값 미사용 함수
print("\(a*b)")
return a+b
}//경고가 나올 수도 있다 하지만 실행해보니 안나옴
addFunction(2,3) //6
@discardableResult func say(_ name: String) -> String {
print(name)
return name
}
say("mine") //mine