Fuction 이란?
독립적으로 처리가 가능한 부분을 분리하여 정해진 처리 과정에 따라 출력 값을 반환하는 과정을 말합니다.
1-1. 함수의 기본형태
func 함수이름 (매개변수1:타입, 매개변수2:타입) -> 반환 타입 {
실행내용
return 반환값
}
함수의 이름을 만들고 매개변수 이름을 만들며 매개변수의 타입을 정합니다. 매개변수는 영어로 parameter라고 부르며 함수를 호출할 때 전달되는 값을 전달하는 이름과 타입을 정의합니다. 그다음 반환 타입을 작성합니다. 반환 타입은 함수로 인해 생성된 값의 타입을 지칭하는 것으로 한번 지칭된 타입은 해당 타입의 값만 반환할 수 있습니다.
// 매개변수와 반환값이 모두 없는 함수
func sayHello () {
print("hello")
}
// 매개변수는 없고 반환값만 있는 함수
func sayHello () -> String {
let returnValue = "Hello"
return returnValue
}
// 매개변수는 있고 반환값이 없는 함수
func sayHello (name:String) {
print ("Hello \(name)"
}
// 매개변수도 있고 반환값도 있는 함수
func sayHello (name:String) -> String {
let returnValue = print ("Hello \(name)")
return returnValue
}
매개변수가 없다면 매개변수를 비우고 ()만 넣으면 됩니다. 반환 값이 없다면 반환 타입을 작성하지 않아도 됩니다. 반환값의 유무의 차이는 반환값이 있을 경우 다른 곳에 값을 대입이 가능합니다. EX) mylabel.text = sayHello()
1-2. 함수의 호출
sayHello ()
함수를 호출하기 위해서는 해당 함수의 이름을 쓰고 ()를 붙여 줍니다. 위의 함수에서 쓴 ()와 함수 호출에서 쓴 ()가 다른 점이 있다면 함수를 만들 때 썼던 ()는 매개변수를 선언하기 위한 역할이었다면 호출에서의 ()는 함수를 호출하는 연산자입니다.
sayHello (name:"김떙땡")
만약 매개변수가 없는 함수라면 위의 예시처럼 매개변수 없이 함수를 호출하면 되지만 매개변수를 가지고 있는 함수라면 함수를 호출할 때 () 안에 인자 레이블과 인자 값을 넣어 호출해야 합니다. 여기서 인자 값이란 매개변수에 입력되는 값을 인자 값이라고 지칭하고 인자 레이블이란 매개 변 수명이라고 생각하면 됩니다. 인자 값의 타입은 앞에 넣었던 매개변수의 타입과 일치해야 합니다.
1-3. 함수의 반환 값과 튜플
함수에서 여러 개의 값을 반환하고 싶다면 배열, 딕셔너리, 집합, 구조체 등을 사용할 수 있지만 튜플을 먼저 보겠습니다.
func info () -> (Int, String) {
let height = 190
let name = "Harry"
return (height, name)
}
func detailInfo () -> (Int, Character, String){
let gender:Character = "M"
let height = 190
let name = "Harry"
return (height, gender, name)
}
반드시 반환 타입에 맞는 반환 값이 들어가야 합니다.
var infosearch = detailInfo()
infosearch.0 // 190
infosearch.1 // "M"
infosearch.2 // "Harry"
var (a,b,c) = detailInfo()
a // 190
b // "M"
c // "Harry"
var (height, _, name) = detailInfo()
튜플의 인덱스를 활용하여 반환 값을 변수나 상수를 이용하여 사용할 수 있습니다. _는 변수 할당 없이 건너뛸 수 있습니다.
func detailInfo () -> (h:Int, g:Character, n:String) {
let gender:Character = "M"
let height = 190
let name = "Harry"
return (height, gender, name)
}
var result = detailInfo()
result.h
result.g
result.n
튜플의 반환 값에 변수를 할당하면 자동으로 바인딩되어 함수의 반환 값을 받는 변수에도 자동 적용됩니다.
typealias infoType = (Int, Character, String)
func detailInfo () -> infoType {
let gender:Character = "M"
let height = 190
let name = "Harry"
return (height, gender, name)
}
var infosearch = detailInfo()
infosearch.0 // 190
infosearch.1 // "M"
infosearch.2 // "Harry"
타일 알리아스를 사용해서 코드를 줄일 수 있으며 타입 알리아스는 타입만 정의할 수 있기 때문에 구체적인 값은 들어갈 수 없고 튜플과 동일한 형태로 취급됩니다.
typealias infoType = (h:Int, g:Character, n:String)
func detailInfo () -> infoType {
let gender:Character = "M"
let height = 190
let name = "Harry"
return (height, gender, name)
}
var infosearch = detailInfo()
infosearch.0 // 190
infosearch.1 // "M"
infosearch.2 // "Harry"
타입 알리아스를 사용하였더라고 튜플과 동일하게 사용이 가능합니다.
2. 매개변수
2.1 내부 매개변수와 외부 매개변수
func sayHello (person:String, anotherPerson:String) -> String {
return "Hello \(person) and \(anotherPerson)!"
}
print (sayHello(person:"Bill", anotherPerson:"Ted"))
func sayHello (to person:String, and anotherPerson:String) -> String {
return "Hello \(person) and \(anotherPerson)!"
}
print (sayHello(to:"Bill", and:"Ted"))
위의 예제는 내부 매개 변수만 사용한 예시이고 아래 예제는 외부, 내부 매개변수를 같이 사용한 예입니다. 외부 매개변수는 내부 매개변수 앞에 사용되며 외부 매개변수는 함수를 호출할 때 인자 값에 대한 레이블과 함수의 식별자로서 사용되고 내부 매개변수는 입력된 인자 값을 함수 안에서 참조하기 위해 사용하는 변수입니다.
func sayHello (_ person:String, _ anotherPerson:String) -> String {
return "Hello \(person) and \(anotherPerson)!"
}
print (sayHello("Bill","Ted"))
외부 매개변수는 _를 사용해서 생략이 가능합니다.
func sayHello (to person:String, _ anotherPerson:String) -> String {
return "Hello \(person) and \(anotherPerson)!"
}
print (sayHello(to:"Bill","Ted"))
func sayHello (person:String, and anotherPerson:String) -> String {
return "Hello \(person) and \(anotherPerson)!"
}
print (sayHello("Bill", and:"Ted"))
여러 개의 외부 매개변수가 있을 경우에도 일부만 생략이 가능합니다.
2.2 가변 인자
func arithmeticMean (numbers : Double...) -> Double {
var total : Double = 0
for number in numbers {
total += number
}
return total / Double(number.count)
}
arithmeticMean (1,2,3,4,5)
함수는 정의된 형식과 개수가 맞는 인자 값만 처리할 수 있지만... 범위 연산자를 사용하여 가변적인 개수의 인자를 처리할 수 있습니다. Double... 가변적인 개수를 나타내며 arithmeticMean (1,2,3,4,5)에 가변적인 개수를 넣을 수 있습니다.
2.3 기본값이 있는 매개변수
func someFunction (parameterWithDefault : Int = 12) {
// function body goes here
// if no arguments are passed to the function call,
// value of parameterWithDefault is 12
}
someFunction (6) // parameterWithDefault is 6
someFunction () // parameterWithDefault is 12
매개변수에 기본값을 저장하여 출력할 수 있습니다. someFunction 함수에 매개변수 12를 기본값으로 넣으면 함수를 출력할 때 매개변수를 지정하지 않는다면 기본값 12가 그대로 출력되고 만약 다른 숫자를 넣는다면 해당 숫자의 인자 값으로 함수가 실행됩니다.
2.4 Inout 매개변수
func some (a:Int) -> Int {
a = a+1
return a
}
some (1)
// Error 발생
매개변수의 인자 값은 기본적으로 상수로 설정되어있습니다. 만약 매개변수의 인자 값이 변수 였다면 위의 예시에서 인자값 1을 매개변수에 넣는다면 a=2가 되어야 정상이지만 매개변수는 상수로 설정되어있기 때문에 오류가 발생합니다. 이는 인자값이 변수였다 하더라도 값을 복사하여 상수로 설정합니다.
func some (a:Int) -> Int {
var a = a
a = a+1
return a
}
some (1)
하지만 상수로 정의된 인자 값을 변수로 바꿀 수 있는 방법이 존재합니다. 매개변수의 이름과 똑같은 변수를 하나 만들어 주면 됩니다. 위의 예시처럼 a라는 변수를 만들고 =a를 대입하면 a는 더이상 매개변수의 값이 아닌 변수의 값이 됩니다. 위의 예시처럼 굳이 똑같은 이름으로 만들 필요는 없습니다.
var someInt = 20
func example(a : Int) -> {
var a = a
a += 1
return a
}
print(example(a:someInt)) // 함수 내부의 값은 21
print(a) // 함수 외부의 값은 20
하지만 위의 예시에도 단점은 있습니다. 함수의 특성상 함수 내부에서 처리된 값은 외부에는 영향을 줄 수가 없습니다. example 함수를 호출하고 인자 값을 20을 주었을때는 호출된 example은 함수 내부의 계산에 따라 값 21을 반환하지만 함수 밖에 있는 a의 값은 21이 아닌 20으로 함수의 영향을 받지 않았습니다. 이를 해결하기 위해 Inout 매개변수를 사용합니다.
var someInt = 20
func example(a : inout Int) -> {
a += 1
return a
}
print(example(a : &someInt)) // 함수 내부의 값은 21
print(a) // 함수 외부의 값은 21
맨 앞의 예시와 다르게 인자 값을 변수로 바꾸지 않았어도 오류가 나지 않을 뿐더러 함수 내부에서 처리된 값이 외부까지 영향을 주고 있습니다. inout은 값에 저장된 메모리 주소를 불러온다는 뜻입니다. 이 말은 복사와 참조의 차이를 말합니다. 처음 예시같은 경우는 인자값을 전달하면 값을 복사하여 함수를 실행합니다. 복사는 말 그대로 똑같은 값을 복사하기 때문에 원본 값에는 어떠한 손상도 주지 않기 때문에 값이 내부는 20 외부는 21로 달랐습니다. 그러나 input같은 경우는 인자값이 저장된 근본적인 메모리 주소를 찾아서 똑같은 값을 복사가아닌 참조하기 때문에 인자값을 그대로 가져오게 되고 이는 외부에도 값에도 영향을 미쳐 내부 외부 모두 21이 됩니다. 앞서 말했듯이 inout은 메모리 주소를 가져온다는 뜻이기 때문에 인자값을 전달할 값 앞에 메모리 주소 추출 연산자인 &를 꼭 붙여주어야 합니다.
var someInt = 20 // 오직 변수만 가능
let someInt = 20 // 상수는 불가능
func example(a : inout Int) -> {
a += 1
return a
}
print(example(a : 20)) // 리터럴 값은 불가능
print(example(a : &someInt)) // 변수와 &연산자를 붙여 가능함
print(a) // 함수 외부의 값은 21
inout 매개변수는 원본을 수정할 수 있기 때문에 상수는 불가능하며 리터럴 역시 될 수가 없습니다.
'Swift 문법정리' 카테고리의 다른 글
1.3 Classes and Structures Method정리 (0) | 2020.05.21 |
---|---|
1.2 Classes and Structures Property 정리 (0) | 2020.05.14 |
1.1 Classes and Structures 정리 (0) | 2020.05.13 |
Collection Types 정리 (0) | 2020.05.08 |
Optional 정리 (0) | 2020.05.08 |