本日は 無所有参照
を 暗黙アンラップされるオプショナル
と併用する話の中で出てきたサンプルコードを見ていたときに気になった事柄のもうひとつについて番外編みたいな感じで眺めていきます。サンプルコードでは クラス
で型を定義していましたけれど、あまり Swift でクラスを定義する機会は少ない気がします。それに倣ってサンプルコードで出てきた クラス
を 構造体
に定義し直したらどんな雰囲気になってくるのか、そんな観点で眺めていってみることにしますね。よろしくお願いします。
—————————————————————————————— 熊谷さんのやさしい Swift 勉強会 #246
00:00 開始 00:32 最近のおさらい 04:35 意味する値とインスタンスとの一致性の問題 05:57 今回は構造体で値表現を行ってみる 07:29 値表現にクラスを選ばない理由 10:55 クラスと比べた構造体の欠点としては 11:48 構造体のその他の利点としては 14:27 クラスだとプロトコルを適用できないことがある 15:40 構造体は Swift による手厚いサポートも魅力 17:21 値表現をクラスから構造体に変えてみる 19:18 全項目イニシャライザー 21:07 全項目イニシャライザーの自動実装は公開されない 25:32 値型の循環定義 26:28 今回の所感と次回の展望 ——————————————————————————————
Transcription & Summarize : 熊谷さんのやさしい Swift 勉強会 #246
さて、今日の勉強会は久しぶりですね。前回は一週間前でしたが、今日は前回の続きとなります。前回の話を覚えていなくても問題ないと思います。
さて、本編で見ているのは、無所有参照(unowned reference)とオプショナル型(Optional)を組み合わせて使う場面です。この例として、国(Country)と首都(Capital City)を持つ都市(City)の例を見ていました。
前回の雑談では、プロパティの初期化順序やインスタンス化について話をしました。具体的には、オプショナル型について議論し、サンプルコードでは必ず国に所属する形を取っていました。都市が必ず国に所属するという前提で、unowned
参照を使う例です。let
プロパティは基本的に値がある前提で、表示上は強制アンラップ(強制的にアンラップするために!
を使用)するオプショナル型にしていました。
例では、日本の都市「東京」を初期化する際に、国を必ず指定しなければならず、国を初期化するには首都が必要で、その初期化順序が難しいといった話をしました。例えば、国を初期化するときに首都「東京」を持つようにするわけですが、この順序がややこしいと感じる部分でした。
今回は、Swiftでのクラスの使用についてもう一度考えます。具体的には、データ型をクラスで表現するのが適切なのかについてです。実際には、Swiftでは構造体(Struct)が一般的に使われます。理由としては、クラスは参照型として扱われ、他方、構造体は値型として扱われるためです。このため、値型を利用するとSwiftの言語仕様により安全性が担保されます。
例えば、マルチスレッド環境では、予期しない値の変化を防ぐことができます。また、パフォーマンスの向上も期待できます。スタックの利用や、呼び出し追跡などがその例です。
一方、構造体を使う際の欠点も存在します。メモリー使用量が増えるのと、コピーのコストがあります。しかし、構造体はオブジェクト思考と比べて定義が簡単です。継承の概念がないため、設計がシンプルになります。
さらに、プロトコルの適用もクラスより構造体のほうが優れています。クラスだとプロトコルを適用できないことがあるため、プロトコル志向の設計では構造体が有利です。
これらの理由から、都市(City)のデータ型をクラスではなく構造体(Struct)で定義してみます。まず、与えられた属性を持つ構造体を作成し、無所有参照を活用することで循環参照を防ぎます。
構造体を定義すると、Swiftでは自動でメンバーワイズ初期化子(Memberwise Initializer)が備わります。これにより、初期化子を一つ一つ定義する手間が省け、コードの可読性も向上します。
サンプルに戻り、クラスの使用を避け、構造体として定義した場合には、名前と所属国を含むデータ型を構造体で実装します。構造体を使うことでデータ型の定義が簡単になり、読みやすさも向上します。
しかし、ライブラリとして使う際に、メンバーワイズ初期化子が内部的(internal)になってしまう点は注意が必要です。これをパブリック(public)に変更する方法として、リファクタリングツールを使用することが考えられます。
次回はこの辺りの詳細や、循環参照問題についてもう少し掘り下げていく予定です。今回のまとめとして、Swiftのクラス使用を避け、構造体を使うことの利点について話しました。次回もこの話題の続きを見ていきたいと思います。では、今日はここまでにしておきましょう。 その内容について説明しますね。Swiftでは、変数と定数があります。変数はvar
、定数はlet
を使って宣言します。変数は値を変更できますが、定数は一度値を設定すると変更できません。
次に、データ型について説明します。Swiftには様々なデータ型があります。例えば、整数型のInt
、浮動小数点数型のDouble
やFloat
、文字列型のString
などです。Swiftは型推論が強力なので、明示的に型を指定しなくても、適切な型を自動的に判断してくれます。
また、Swiftでは関数の定義も簡単です。関数はfunc
キーワードを使って定義します。例えば、次のようにして二つの整数の和を計算する関数を定義できます:
func add(a: Int, b: Int) -> Int {
return a + b
}
ここで、add
という名前の関数を定義し、二つのInt
型の引数を取って、その合計を返します。
次に、条件分岐について説明します。条件分岐にはif
、else if
、else
を使います。以下に簡単な例を示します:
let score = 85
if score >= 90 {
print("Excellent!")
} else if score >= 75 {
print("Good job!")
} else {
print("Keep trying!")
}
この例では、score
が90以上の場合「Excellent!」、75以上の場合「Good job!」、それ以外の場合「Keep trying!」と表示されます。
このように、Swiftの基本的な文法を押さえることで、様々なプログラムを作ることができます。他にも、ループやコレクション、エラーハンドリングなど、重要なトピックがありますが、まずはこれらの基本をしっかり理解しておくことが大事です。 もちろんです。文字起こしのテキストをこちらに提供していただければ、自然な文章に整えていきます。テキストをどうぞ。 テキストが提供されていないようです。動画の文字起こしテキストを提供していただければ、整形と訂正を行いますので、再度テキストを送ってください。 完全自動化までは行かなくてもいいですが、先ほど言ったように、実装だけでも自動化されると便利ですよね。実装を書かなくてもいいというのは、非常に魅力的です。
特にライブラリやマイクロモジュールなど、最近はやりの小さなモジュールに分けると、管理が面倒です。例えば、メンバーワイズイニシャライザーを揃えるのが大変なので、自動的に生成されると助かりますよね。それにパブリックを付けないという部分も、理解できます。
一旦、どんなにしても良いという前提で考えつつ、このローカルなプロジェクトに閉じた場合、基本的に今の書き方で完成してしまう構造体は問題ありません。定義だけの話になりましたが、使う面でも多くの利点があり、美味しいところがいっぱいです。基本的にはデータを構造体で作ると良いことが多い、という感じですね。
さて、時間になりましたので、今日はこれぐらいにして、次回は困った問題についてじっくり見ていこうかなと思います。順番の定義になっているのですが、なぜこうなっているのか、どう解釈すればいいのか、現時点では分かりませんが、ゆっくりやっていきましょう。
以上で、今日の勉強会を終わります。お疲れ様でした。ありがとうございました。