[Swift] struct の initializer おさらい

     

TAGS:

struct の initializer をまとめます。

環境&対象

以下の環境で動作確認を行なっています。

  • macOS Monterey 12.4 beta
  • Xcode 13.3
  • iOS 15.4

Struct の initializer は、3種類

大きくわけて 3つあります。
・すべてのプロパティが初期値を持つとき使用できる default initializer
・自動で用意される memberwise initializer
・自分で定義して使う custom initializer

default initializer

struct 内に定義されている stored property のすべてに 初期値が設定されていて、initializer が1つも定義されていない時には、default initializer が使用できます。


import Foundation

struct Person {
    var name: String = "John Doe"
    var age = 18
}

let johnDoe = Person() // name: "John Doe"  age: 18

上記の struct Person 内に定義されている プロパティ name, age のそれぞれに初期値が設定されています。Person() とすると default initializer が使用され、struct を インスタンス化することができます。
プロパティには、それぞれの初期値が設定されます。
ただし、initializer を1つでも自分で定義していると使用できなくなります。
default initializer を使っているコードは、別の initializer を定義するとコンパイルエラーになります。

なお、自分で、init() を定義すると default initializer ではなく、自分が定義した init() が使用されます。


import Foundation

struct Person {
    var name: String = "John Doe"
    var age = 18
    init() {
      name = "Jane Doe"
      age = 20
    }
}

let janeDoe = Person() // name: "Jane Doe"  age: 20

memberwise initializer

memberwise initialier は、struct の持つプロパティを個別に指定することができるようになっている initializer です。自動で作成されます。(定義せずとも使用できます)


import Foundation

struct Person {
    var name: String = "John Doe"
    var age = 18
}

let janeDoe = Person(name: "Jane Doe", age: 18) // -- memberwise initializer

ただし、initializer を1つでも自分で定義していると使用できなくなります。
memberwise initializer を使っているコードは、別の initializer を定義するとコンパイルエラーになります。


struct Person {
    var name: String = "John Doe"
    var age = 18
    init() {
        name = "test"
        age = 9
    }
}

let johnDoe = Person()
let janeDoe = Person(name: "Jane Doe", age: 18)   // -- Compile Error !
MEMO
自分で定義する custom initializer を extension で定義すると、それまで通り、memberwise initializer も使用できます。

import Foundation

struct Person {
    var name: String = "John Doe"
    var age = 18
}
extension Person {
    init(name: String) {
        self.name = name
        self.age = 18
    }
}
let nanashi = Person(name: "Nanashino Gonbe", age: 20) // memberwise initializer

なお、初期値が設定されているプロパティについては、memberwise initializer から省略することが可能です。


import Foundation

struct Person {
    var name: String = "John Doe"
    var age = 18
}

let johnDoe = Person()
let janeDoe = Person(name: "Jane Doe") // - age を省略すると 初期値の 18 が設定される

custom initializer

default initializer, memberwise initializer は、自動で用意される initializer でしたが、自分で initializer を定義することができます。それが custom initializer です。custom initializer は必要な分だけ 複数定義できます。

以下は、外部から与えられた値によって設定する値を変える例です。
Person の name 情報しか受け取らず、name の値に応じて age を設定するような custom initializer です。

使用している三項演算子は、以下の記事で説明してます。


import Foundation

struct Person {
    var name: String = "John Doe"
    var age = 18
    init(name: String) {
        self.name = name
        self.age = name == "John Doe" ? 18 : 20
    }
}

let johnDoe = Person(name: "John Doe") // age 18 
let janeDoe = Person(name: "Jane Doe") // age 20

通常の関数と同じように柔軟に書くことができますが、以下のことに気をつける必要があります。

・すべての stored property は initializer が終わる段階で 値が設定されている必要がある。
・initializer 内から、struct のインスタンスメソッドを呼び出すには、それ以前に すべての stored property が設定されている必要がある。

struct は、継承できないので、super.init() を使って、プロパティの初期化をすることはできませんが、1つの initializer から別の initializer を呼ぶことは可能です。このことを使って 初期化コードを共通化することができます。

failable initializer

初期化に失敗することがある/できる initializer を書くこともできます。failable initializer と呼ばれます。

以下のように名称を init? と定義することで failable initializer になり、nil を返すことができるようになります。
なお、返り値は optional になるので、使う側ではチェックが必要となります。


import Foundation

struct Person {
    var name: String = "John Doe"
    var age = 18
    init?(name: String, age: Int) {
        if age < 18 {
            return nil
        }
        self.name = name
        self.age = age
    }
}

let johnDoe = Person(name: "Jane Doe", age: 17)  // nil が返される

class の initializer

class の initializer については、以下でまとめています。
[Swift] 脱初心者 class initializer おさらい(1: designated initializer と convenience initializer) [Swift] 脱初心者 class initializer おさらい(2: クラス継承と required initializer) [Swift] 脱初心者 class initializer おさらい(3: failable initializer)

まとめ

struct の initializer についてまとめました。

struct の initializer についてのまとめ
  • 初期値を設定すると default initializer が使える
  • デフォルトで memberwise initialize が使える
  • class の initializer と同様に failable initializer も作成できる
  • custom initializer を使うと与えた条件に応じた初期値を持つインスタンス化が可能となる

説明は以上です。
不明な点やおかしな点ありましたら、こちらまで。

コメントを残す

メールアドレスが公開されることはありません。