---
layout: post
title: [스위프트 대충보기] 5. 함수
tags: 스위프트, swift, 함수, function, 매개변수, 파라미터, 인자, parameter, argument, 외부이름, external name, 반환타입, return type, 일등객체, 내포함수
---
[스위프트 대충보기] 5. 함수
-
함수: 정해진 과업을 수행하는 독립적인 코드 덩어리로 함수에 이름을 부여해 두면, 나중에 이를 호출할 수 있다
-
함수 정의하기:
func 함수이름(매개변수이름: 매개변수타입) -> 반환타입 { 함수 본문 }
-
함수에서 값을 반환할 때는 return을 사용
func sayHello(personName: String) -> String { let greeting = "Hello, " + personName + "!" return greeting }
-
함수 호출하기:
함수이름(인자)
sayHello("예쁜이")
-
함수 인자가 없으면
()
, 여럿 있으면(매개변수1:타입1, 매개변수2: 타입2)
식으로,
로 구분 -
함수에 반환값이 없는 경우에는 반환 타입 부분(함수 인자 목록 다음의
-> 반환타입
)을 없앤다. 이경우 함수의 반환 타입은Void
이며,()
라고 표현한다(빈 튜플).func sayGoodbye(personName: String) { println("Goodbye, \(personName)!") }
-
함수가 값을 반환해도, 호출하는 쪽에서 이를 무시할 수 있다. 그렇지만
Void
를 반환하는 함수가 아닌 경우 반드시 값을 반환하는return
문이 있어야만 한다. -
여러 리턴 값을 반환하고 싶으면 튜플을 사용한다. 이때, 이름붙은 튜플을 사용하고 싶으면, 함수 리턴타입 부분에 명시하면 된다(!).
func count(string: String) -> (vowels: Int, consonants: Int, others: Int) { var v = 0, c = 0, o = 0 for character in string { switch String(character).lowercaseString { case "a", "e", "i", "o", "u": ++v case "b", "c", "d", "f", "g", "h", "j", "k", "l", "m", "n", "p", "q", "r", "s", "t", "v", "w", "x", "y", "z": ++c default: ++o } } return (v, c, o) }
-
튜플에서 이미 본대로, 위 함수의 리턴값은 각각
.vowels
,.consonants
,.others
로 액세스할 수 있다.let total = count("some arbitrary string!") println("\(total.vowels) vowels and \(total.consonants) consonants") // "6 vowels and 13 consonants" 출력
-
objective C처럼 외부에서 호출시 매개변수 이름을 지정하게 하고 싶으면, 외부 이름을 지정해야 한다.
(외부이름 내부이름: 타입)
과 같은 형태로 지정하며, 함수 내부에서는 내부이름으로 인자로 받은 값을 참조한다. 가능하면 외부이름을 지정하는걸 권장한다.func join(string s1: String, toString s2: String, withJoiner joiner: String) -> String { return s1 + joiner + s2 } join(string: "hello", toString: "world", withJoiner: ", ")
-
매개변수의 외부이름을 따로 적지 않고, 내부이름 앞에
#
를 붙이면 내부이름과 외부이름을 같게 만들 수 있다.func containsCharacter(#string: String, #characterToFind: Character) -> Bool { for character in string { if character == characterToFind { return true } } return false } let containsAVee = containsCharacter(string: "aardvark", characterToFind: "v")
-
함수 내부에서는 매개변수 이름을 자유롭게 사용 가능하다. 특별히 지정하지 않으면 매개변수는 상수이다. 내부에서 매개변수에 값을 대입할 수 없다.
-
디폴트 매개변수 값을 지정할 수 있다. 디폴트 값 지정은 매개변수의 맨 뒤에 있어야 한다.
func join(string s1: String, toString s2: String, withJoiner joiner: String = " ") -> String { return s1 + joiner + s2 } join(string: "hello", toString: "world") // "hello-world" join(string: "hello", toString: "world", withJoiner: "-") // "hello world"
-
디폴트 매개변수 값을 지정하는 경우 스위프트가 자동으로 해당 매개변수 이름을 외부 이름으로도 사용한다.
func join(s1: String, s2: String, joiner: String = " ") -> String { return s1 + joiner + s2 } join("hello", "world", joiner: "-") // "hello-world"
-
이 경우, 이 기능을 무력화시키려면
_
로 외부 이름을 적으면 강제로 외부이름이 없어진다.func join(s1: String, s2: String, _ joiner: String = " ")
-
가변길이 매개변수(variadic parameter)도 지원한다. 가변길이 매개변수는 함수 매개변수 목록의 맨 뒤에 있어야 하며, 타입 뒤에
...
을 넣으면 된다. 함수 본문에는타입[]
(즉, 타입이 원소인 배열)으로 전달받으므로 배열을 액세스하면 된다.// 안돌려봤음. 오류 생기면 알아서 수정하삼. func sum(x:Double, y:Double) -> Double { return x + y } func arithmeticMean(numbers: Double...) -> Double { val total = numbers.reduce(0, sum) // 심심하니 리듀스를... return total / Double(numbers.count) }
-
가변길이 매개변수와 디폴트 값이 있는 매개변수가 함께 있는 함수는 맨 나중에 가변길이 매개변수, 그 바로 앞에 디폴트 매개변수 순으로 배치해야 한다. 즉,
func foo(s1: Int, s2: String, dfltArg: String = " ", arrArg: Int...) -> String
-
기본적으로 함수 매개변수는 상수이며(본문 안에서 대입/변경 불가), 원하면 파라미터 이름 앞에
var
를 붙여서 변경 가능하게 바꿀 수 있음. 하지만, 변경 가능하다고 해도 함수 안에서만 작용함.// 잘못 만든 swap. 이런짓 하면 혼남 func swap(var x:Double, var y:Doube) { let t = x x = y y = t } var w1 = 10, w2 = 20 println("w1=\(w1) w2=\(w2)") swap(w1,w2) println("w1=\(w1) w2=\(w2)")
-
위 swap을 가능하게 하려면 매개변수 이름 앞에
inout
을 붙인다. -
다만,
inout
매개변수에 값을 변경하기 위한 무언가를 넘기려면&
를 앞에 붙여서, 그 값이 함수 실행 이후 변할 수 있음을 표시해야 한다.inout
변수는 함수 리턴값과는 별개임에 유의하라.func swap(inout x:Double, inout y:Doube) { let t = x x = y y = t } var w1 = 10, w2 = 20 println("w1=\(w1) w2=\(w2)") swap(&w1,&w2) println("w1=\(w1) w2=\(w2)")
-
함수의 타입은
(매개변수타입들) ->
반환타입 이다. 다음 두 함수는 타입이 같다.func addTwoInts(a: Int, b: Int) -> Int { return a + b } func multiplyTwoInts(a: Int, b: Int) -> Int { return a * b }
-
매개변수가 없으면
()
, 반환값이Void
면 반환값 부분이()
이므로, 아무 인자도 안받고, 아무 반환값도 없는 함수의 타입은()->()
이다.
-
함수는 1등객체이기 때문에, 함수를
let
이나var
를 사용해 변수/상수에 대입 가능하다.var mathFunction: (Int, Int) -> Int = addTwoInts println("10+20 = \(mathFunction(10,20))")
-
1등객체니까 당연히 매개변수로 전달할 수도 있다.
func reduceIntArrayByIteration(a0:Int, arr: Int[], f: (Int,Int)->Int) -> Int { var result = a0 for x in arr { result = f(result, x) } return result }
-
당연히 함수를 반환할 수도 있다.
func stepForward(input: Int) -> Int { return input + 1 } func stepBackward(input: Int) -> Int { return input - 1 } func chooseStepFunction(backwards: Bool) -> (Int) -> Int { return backwards ? stepBackward : stepForward }
-
함수를 내포시킬 수도 있다. 위 chooseStepFunction 다음과 같이 바꿀 수 있다.
func chooseStepFunction(backwards: Bool) -> (Int) -> Int { func stepForward(input: Int) -> Int { return input + 1 } func stepBackward(input: Int) -> Int { return input - 1 } return backwards ? stepBackward : stepForward }
감상: 할말 없음. 당연하지.. 그렇지.. 하고 넘어가게 해준게 스위프트의 장점인듯...