LoginSignup
33
32

More than 5 years have passed since last update.

Swiftのタプルと引数・戻り値

Last updated at Posted at 2014-11-26

 せっかく調べたのでメモ。ただし、その前にクロージャについてメモ。

クロージャ

 抽象的な文法はこちら。

{ (parameters) -> return type in
    statements
}

 省略方法は色々。

// もっとも長い
{ (m: Int, n: Int) -> Int in
    return m + n
}
// 引数・戻り値の型を省略
{ m, n in return m + n }
// returnを省略
{ m, n in m + n }
// 識別子すら省略
{ $0 + $1 }
// 何もかも省略、演算子のみ
[1,2,3].reduce(0, +)

クロージャの代入

 基本的には、そのまま代入すればOK (単なる演算子は除く)。

let x = { (m: Int, n: Int) -> Int in
    return m + n
}

 データ型が推論できない場合でも、引数・戻り値を明示すれば省略を使えます。

let x: (Int, Int) -> Int = { $0 + $1 }

 個人的には、こういう書き方のほうが分かりやすい気がします。
 ちなみに併用もできます (詳細は後述)。

let x: (Int, Int) -> Int = {
    (m: Int, n: Int) -> Int in
    return m + n
}

タプル

 タプルを書くのは括弧で挟むだけ。簡単。

let n = (100, 200)

 名前付きタプルにするのも名前を書くだけ。簡単。
 使うときには n.0 でも n.weight でも通ります。

let n = (weight: 100, height: 200)

 部分的に名前付きタプルにするのも簡単。

let n = (100, height: 200)

引数としてのタプル

※ よく分からないまま書いています
※※ Playgroundで試しています
※※※ varで宣言すると引数にできません

 「Swiftにおける名前付き引数」と「関数引数としてのタプル」の2つを突き合わせながら試行錯誤したところ、引数の仕様は次のようになっているようです。

関数

 関数の引数は、原則として名前なしのタプルです。

func testFunc(hoge: Int, fuga: Int) -> Int {
    return hoge + fuga
}

let n = (1, 2)
testFunc(n)

 引数を名前付きにすると、タプルも名前付きにしなければなりません。

func testFunc(#hoge: Int, #fuga: Int) -> Int {
    return hoge + fuga
}

let n = (hoge: 1, fuga: 2)
testFunc(n)

 部分的に名前付き引数にしても同様です。

func testFunc(hoge: Int, #fuga: Int) -> Int {
    return hoge + fuga
}

let n = (1, fuga: 2)
testFunc(n)

クロージャ

 クロージャの引数も、原則として名前なしのタプルです。

let testClosure  = {
    (hoge: Int, fuga: Int) -> Int in
    return hoge + fuga
}

let n = (1, 2)
testClosure(n)

 しかし、明示的に「名前付き引数のクロージャ」として宣言すると、名前付きタプルが引数になります。部分的に名前付き引数にしても同様です。

let testClosure: (Int, fuga: Int) -> Int = { $0 + $1 }

let m = (1, fuga: 2)
testClosure(m)

 これを利用すると、メンバー関数のような使い方のクロージャも作れます。

let addNumber: (Int, with: Int) -> Int = {
    x, y in
    return x + y
}

addNumber(1, with: 2)

 書き方が違うだけで、関数の挙動とよく似ています。“Functions are actually a special case of closures” という意味が分かるような気がします。

メンバー関数

 原則として、「2つ目以降が名前付きになっているタプル」が引数です。
 この例で言えば、(Int, Int) ではなく (Int, fuga: Int) が引数です。

class TestClass {
    func testFunc(hoge: Int, fuga: Int) -> Int {
        return hoge + fuga
    }
}

let test = TestClass()
let n = (1, fuga: 2)
test.testFunc(n)

戻り値としてのタプル

 Swiftでは、戻り値をタプルにできます。

func testFunc() -> (Int, Int) {
    return (10, 20)
}

 使い道がピンときませんが、戻り値を名前付きタプルにすることもできます。

func testFunc() -> (name: String, age: Int) {
    return ("John", 20)
}

雑記

 Swiftにおいて、括弧で挟まれた記述はみんなタプルです。たとえばメンバー関数を使うために test.testFunc(1, fuga: 2) と書くのは、部分的に名前付きのタプル (1, fuga: 2)を引数として渡すのと同じであり、実際そのように書くことができます。
 つまり、(Int, Int) ではなく (Int, fuga: Int) という「部分的に名前付きのタプル」がひとつの型・ひとつの引数として処理されているようです (たぶん)。

 Swiftにおける引数名の仕様は、外部引数名・ローカル引数名というポリシーの問題ばかりでなく、「名前なしのタプルが引数か、それとも (部分的あるいは全面的に) 名前付きのタプルが引数か」という引数のデータ型の問題として捉えてもいいかもしれません。

 なお変数を引数にできない理由は今のところ不明です。

33
32
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
33
32