Skip to content

Latest commit

 

History

History
executable file
·
198 lines (142 loc) · 8.82 KB

[스위프트 대충보기] 5. 함수.md

File metadata and controls

executable file
·
198 lines (142 loc) · 8.82 KB
Error in user YAML: (<unknown>): did not find expected key while parsing a block mapping at line 1 column 1
---
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 매개변수, inout 매개변수

  • 기본적으로 함수 매개변수는 상수이며(본문 안에서 대입/변경 불가), 원하면 파라미터 이름 앞에 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
          }
    

감상: 할말 없음. 당연하지.. 그렇지.. 하고 넘어가게 해준게 스위프트의 장점인듯...