LoginSignup
67
67

More than 5 years have passed since last update.

The Swift Programming Language - Function(関数)をまとめる

Last updated at Posted at 2014-06-04

The Swift Programming Language をまとめるトップ

Function(関数)

デフォルト値の指定ができる
In-Out パラメーター(参照渡し)
ネストもできる

Defining and Calling Functions(関数の定義と呼び出し)

func の後に名前をつけて引数と戻り値を定義する
書式は以下の例を参照

func 関数名(引数変数: 引数型,,,) -> 戻り値型 {
    return 戻り値型
}

例えば

func sayHello(personName: String) -> String {
    let greeting = "ういっす" + personName + "!"
    return greeting
}
println(sayHello("太郎"))
// prints "ういっす太郎!"
println(sayHello("次郎"))
// prints "ういっす次郎!"

以下のようにも書ける

func sayHello(personName: String) -> String {
    return "ういっす" + personName + "!"
}

解説は簡単なので省く

Function Parameters and Return Values(関数の引数と戻り値)

引数と戻り値には何でも指定する事ができ柔軟な仕様になっているとのこと
そりゃそうだろう

Multiple Input Parameters(複数の引数)

以下のように書く

func halfOpenRangeLength(start: Int, end: Int) -> Int {
    return end - start
}
println(halfOpenRangeLength(1, 10))
// prints "9"

Functions Without Parameters(引数無し関数)

以下のように書く

func sayHello() -> String {
    return "こんにちは!"
}
println(sayHello())
// prints "こんにちは!"

Functions Without Return Values(戻り値無し関数)

->型 を指定しなくてよい

func sayGoodbye(personName: String) {
    println("さようなら, \(personName)!")
}
sayGoodbye("太郎")
// prints "さようなら, 太郎!"

NOTE
厳密にいうと Void型 を返している
戻り値を指定して正しく return していない場合、コンパイルエラーとなる

あと、戻り値を指定しても、ただ呼び出しただけの場合、戻り値が無視される

func printAndCount(stringToPrint: String) -> Int {
    println(stringToPrint)
    return countElements(stringToPrint)
}
func printWithoutCounting(stringToPrint: String) {
    printAndCount(stringToPrint)
}
printAndCount("hello, world")
// prints "hello, world" and returns a value of 12
printWithoutCounting("hello, world")
// prints "hello, world" but does not return a value

Functions with Multiple Return Values(複数の戻り値

複数の戻り値を tuple(タプル)を使って返す事ができる

例えば
母音と子音とそれ以外の文字を文字列から数える count という関数を定義してみる

func count(string: String) -> (vowels: Int, consonants: Int, others: Int) {
    var vowels = 0, consonants = 0, others = 0
    for character in string {
        switch String(character).lowercaseString {
        case "a", "e", "i", "o", "u":
            ++vowels
        case "b", "c", "d", "f", "g", "h", "j", "k", "l", "m",
        "n", "p", "q", "r", "s", "t", "v", "w", "x", "y", "z":
            ++consonants
        default:
            ++others
        }
    }
    return (vowels, consonants, others)
}

count関数をつかって任意の文字列から文字をカウントしてみる

let total = count("some arbitrary string!")
println("\(total.vowels) 個の母音と \(total.consonants) 個の子音")
// prints "6 個の母音 13 個の子音"

既にタプルの値に名前があるので、tuple (タプル)個別の値に名前を指定する必要ない

Function Parameter Names(関数の引数名)

関数には引数名を必ず付ける

func someFunction(parameterName: Int) {
    // paremeterName を引数名として、引数の値を参照する
    // このスッコープのみ有効なローカル変数となる
}

External Parameter Names(外面引数名)

引数に名前がつけられる
ローカル変数の前に書く名前が引数名になる
関数を呼び出す時に引数名を指定して値を渡す事ができる
引数の意味が分かりづらいときに使うとよい

func someFunction(externalParameterName localParameterName: Int) {
    // externalParameterNameで受けてこのスコープ内では localParameterName を引数名として、引数の値を参照する
}

例えば

func join(string s1: String, toString s2: String, withJoiner joiner: String)
    -> String {
        return s1 + joiner + s2
}

join(string: "hello", toString: "world", withJoiner: ", ")
// returns "hello, world"

Shorthand External Parameter Names(簡単な外部引数名)

引数に名前をつける時に以下の様に(#)を使うことが出来る

例えば

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")
// containsAVee は true, 理由は "aardvark" は "v" を含むので

Default Parameter Values(引数初期値指定)

引数の初期値が指定されていたら、関数を呼び出す時にその引数を省略することができる

NOTE
初期値を指定した引数は分かりやすくする為に引数の最後に指定することが望ましい

例えば

joiner に初期値 " " を指定

func join(string s1: String, toString s2: String,
    withJoiner joiner: String = " ") -> String {
        return s1 + joiner + s2
}

// 省略して呼び出す事ができる
join(string: "hello", toString: "world")
// returns "hello world"

External Names for Parameters with Default Values(初期値の外部引数について)

Swift では引数に初期値をしていた場合、自動的に外部引数名が割り当てられる
以下の例だと、joiner を明示的に引数名として指定する事ができる

例えば

func join(s1: String, s2: String, joiner: String = " ") -> String {
    return s1 + joiner + s2
}

// (#)の指定が無くても、joiner を外部引数名として指定する事ができる
join("hello", "world", joiner: "-")

Variadic Parameters(可変引数)

ゼロ個または一つ以上の引数を指定する時に使う
(...) を引数の型名の後に続ける

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)
// returns 3.0

NOTE
可変引数を使う時は、初期値指定のある引数より後、つまり、一番最後に指定する

Constant and Variable Parameters(定数と変数引数)

関数の引数はデフォルトは定数
仮に引数の値を変更しようとした場合、コンパイルエラーになる
引数を変更したい場合、変数に再定義する必要がある
var を最初に指定して初期化して複製をつくる

func alignRight(var string: String, count: Int, pad: Character) -> String {
    let amountToPad = count - countElements(string)
    for _ in 1...amountToPad {
        string = pad + string
    }
    return string
}
let originalString = "hello"
let paddedString = alignRight(originalString, 10, "-")
// paddedString は "-----hello"
// originalString は "hello" のまま

In-Out Parameters(In-Out引数、参照渡し)

inout を引数の前にしていすると、参照渡しになる
関数内での変更が関数へ渡されたオリジナルの値にも変更が加わる
inout を使う時は引数に渡される値は var で定義された変数になる
値を渡す時は(&)を使う

例えば

// inout を指定する
func swapTwoInts(inout a: Int, inout b: Int) {
    let temporaryA = a
    a = b
    b = temporaryA
}

var someInt = 3
var anotherInt = 107

// (&)を付ける
swapTwoInts(&someInt, &anotherInt)
println("someInt は \(someInt), そして anotherInt は \(anotherInt) になる")
// prints "someInt は 107, そして anotherInt は 3 になる"

Function Types(関数型)

どんな関数でも型を必ずもっている
型を明示的に指定しない場合、Void を返す
Void は () 空のタプルと同じ

Using Function Types(関数型の利用)

関数自体にも型指定ができる
定数と変数を定義できる

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

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

var mathFunction: (Int, Int) -> Int = addTwoInts
println("結果: \(mathFunction(2, 3))")
println("Result: \(mathFunction(2, 3))")

// var変数なので、別の関すを代入
mathFunction = multiplyTwoInts
println("結果: \(mathFunction(2, 3))")
// prints "結果: 6"

// 以下の用に定義を書かなくても、推論してくれる
let anotherMathFunction = addTwoInts

Function Types as Parameter Types(関数型を引数に)

関数型を引数として使う事ができる

例えば

func printMathResult(mathFunction: (Int, Int) -> Int, a: Int, b: Int) {
    println("Result: \(mathFunction(a, b))")
}
printMathResult(addTwoInts, 3, 5)
// prints "結果: 8"

Function Types as Return Types(関数型を戻り値に)

戻り値に関数型を指定する事ができる

例えば

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
}

var currentValue = 3
let moveNearerToZero = chooseStepFunction(currentValue > 0)
// currentValue > 0 は true なので、stepBackward()関数 を返す
// よって、moveNearerToZero は stepBackward() を参照する

println("ゼロまでカウント開始")
// Counting to zero:
while currentValue != 0 {
    println("\(currentValue)... ")
    // stepBackword()が呼ばれるので、上記 currentValue - 1 される
    currentValue = moveNearerToZero(currentValue)
}
println("zero!")
// 3...
// 2...
// 1...
// zero!

Nested Functions(関数のネスト)

局所的に関数を使いたい場合にネストが使える

例えば
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
}
var currentValue = -4
let moveNearerToZero = chooseStepFunction(currentValue > 0)
// chooseStepFunctionの引数の値はは currentValue > 0 で false なになる
// backwards に false が代入される
// 三項演算子 "?" を使ってその backwards を評価し、
// それが false なので、":" の右の stepForward()関数 を返す
// よって、moveNearerToZero は stepForward() を参照することになる
while currentValue != 0 {
    println("\(currentValue)... ")
    currentValue = moveNearerToZero(currentValue)
}
println("zero!")
// -4...
// -3...
// -2...
// -1...
// zero!
67
67
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
67
67