タコさんブログ

プログラミングメモと小言

Swift Functions メモ

The Swift Programming LanguageのFunctionsセクションのメモ。

関数の定義

Swiftの関数はfuncキーワードから始まり、次のように書く。

func function_name(parameters) -> return_type {
    // 関数ボディ
    return return_value
}


文字列personNameを受け取り"Hello, personName!"を返すsayHello関数は以下のようになる。

func sayHello (personName: String) -> String {
    return "Hello, \(personName)!"
}

sayHello("Anna")  // playgroundでの出力結果:Hello, Anna!


複数のパラメータを渡す場合はカンマで区切る。

func substract(a: Int, b: Int) -> Int {
    return b - a
}

substract(3, 1) // 出力:2


パラメータを必要としない場合は省略できる。

func sayHelloWorld() -> String {
    return "Hello, world"
}

sayHelloWorld()  // 出力:Hello, world


戻り値がない場合は -> return_type の部分を省略することができる。

func sayGoodbye() {
    println("Goodbye")
}

sayGoodbye() // 出力結果:Goodbye

※戻り値がない関数は実際にはVoid型が返る。
Void空タプルで定義されている。
typealias Void = ()


呼び出した関数の戻り値は関数の中では無視される。

func printAndCount(stringToPrint: String) -> Int {
    println(stringToPrint)
    // countElements:文字数を取得する関数
    return countElements(stringToPrint)
}

func printWithoutCounting(stringToPrint: String) {
    printAndCount(stringToPrint)  // 戻り値は無視される
}

printWithoutCounting("hello, world")  // 出力:"hello, world" (戻り値はない)


タプル型を利用して、複数の値を返すこともできる。

func seperateFirstAndLastName(fullName: String) -> (firstName: String, lastName: String) {
    let firstAndLastName = fullName.componentsSeparatedByString(" ")
    return (firstAndLastName[0], firstAndLastName[1])
}

let fullName = seperateFirstAndLastName("Joe Black")
fullName.firstName  //  出力:Joe
fullName.lastName  //  出力:Black

関数のパラメータ

swiftでは外部パラメータ名、デフォルトパラメータ値、可変長引数、In-Outパラメータなどの機能がある。

外部パラメータ名(External Parameter Names)

上記の関数のパラメータは全てローカルパラメータと呼ばれ、関数内部からしか使用できない。外部パラメータ名はローカルパラメータの前に宣言する。

func myFunction(externalParameterName localParameterName: Int) {
    // 関数ボディ
}

下の関数は文字列joinerでs1とs2を結合する。

// 通常の書き方
func join(s1: String, s2: String, joiner:String) -> String{
  return s1 + joiner + s2
}

// 外部パラメータ名を使った書き方
func join(string s1: String, toString s2: String, withJoiner joiner: String) -> String {
      return s1 + joiner + s2
}

関数のボディは同じだが、呼び出し方が違う。

// 通常の書き方
join("hello", "world", ", ")

// 外部引数名を使った書き方
join(string: "hello", toString: "world", withJoiner: ", ")

引数の目的が不明瞭な場合は、外部パラメータ名を使用することで可読性を高めることが目的のようだ。ローカルパラメータ名がすでに外部パラメータとして最適な場合は#を使用して2つの名前を同じにできる。

func containsCharacter(#string: String, #characterToFind: Character) -> Bool {
    for character in string {
        if (character == characterToFind) {
            return true
        }
    }

    return false
}

containsCharacter(string: "abcdedefg", characterToFind: "g")  // 出力:true
デフォルト引数

swiftではデフォルト引数を与えることができる。デフォルト値を与える場合、パラメータの最後に書く。例えば、join関数のjoinerにデフォルト値(スペース)を与えた場合、以下のようになる。

func join(string s1: String, toString s2: String, withJoiner joiner: String = " ") -> String {
      return s1 + joiner + s2
}
// デフォルト値を使用した呼び出し方
join(string: "hello", toString: "world")  // 出力:hello world

デフォルト値を持つパラメータは自動でローカルパラメータ名と同じ外部パラメータ名が与えられる。つまりjoinは以下のように書ける。

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 = " ") -> String {
      return s1 + joiner + s2
}
// デフォルト値を使用した呼び出し方
join("hello", "world", joiner: ", ")  // 外部パラメータがないのでコンパイルエラーになる
可変長パラメータ

任意の数の引数を取る場合は、パラメータの型の後にドット3つ(...)で宣言する。可変長パラメータはパラメータの最後にしか宣言ができないので、関数は最大で1つの可変長パラメータをもつ。

func arithmeticMean(numbers: Double ...) -> Double {
    var total: Double = 0
    for number in numbers {
        total += number
    }
    return total / Double(numbers.count)
}

arithmeticMean(1, 2, 3, 4, 5)  // 出力:3.0

関数のセクションは意外とボリュームがある・・・;
残りの部分は続編を書くことにします。