ProgrammingiOS 開発者

Swiftにおけるサブスクリプションとは何ですか?カスタムサブスクリプトを自分の構造体で実装する方法は?

Hintsage AIアシスタントで面接を突破

回答。

質問の背景:

サブスクリプトは、コレクション、構造体、その他のデータ型の内部の値に対して、角括弧を使用してアクセスするためのメカニズムです。これは、Swiftに追加されたもので、他の言語(たとえば、Pythonの配列のインデックス化、C++/Javaの[]演算子)と同様の方法です。これにより、コレクションや類似のオブジェクトを扱う際に、より直感的になります。

問題:

すべての型がデフォルトで配列のようにインデックスによるアクセスをサポートしているわけではありません。データを持つ構造体やクラスがある場合、要素へのアクセスは、メソッドを使うのではなく、慣れ親しんだ構文(例えば、myObject[index])を使用する方が論理的です。

解決策:

Swiftでは、任意のユーザー定義型に対してサブスクリプトを独自に実装することができます。読み取り専用としても、書き込み専用としても作成できます。以下は、正方行列を操作するためのサブスクリプトを実装した構造体の例です:

struct Matrix { let size: Int private var grid: [Int] init(size: Int) { self.size = size self.grid = Array(repeating: 0, count: size * size) } subscript(row: Int, column: Int) -> Int { get { precondition(indexIsValid(row, column), "範囲外のインデックス") return grid[(row * size) + column] } set { precondition(indexIsValid(row, column), "範囲外のインデックス") grid[(row * size) + column] = newValue } } private func indexIsValid(_ row: Int, _ column: Int) -> Bool { return row >= 0 && row < size && column >= 0 && column < size } } var m = Matrix(size: 3) m[1,2] = 7 print(m[1,2]) // 7

重要な特徴:

  • サブスクリプトは、単一のインデックスだけでなく、任意の数の引数を取ることができます。
  • サブスクリプトは、キーワードsubscriptを使用して実装され、get専用またはget/setのいずれかにすることができます。
  • ユーザー定義のコレクションや構造体のために使いやすく、読みやすいAPIを作成することができます。

ひっかけ問題。

サブスクリプトはコレクションにしか使用できないのですか?

いいえ、サブスクリプトは構造体、クラス、列挙型など、あらゆる型に対して実装できます。データ型が必ずしもコレクションである必要はなく、サブスクリプトを介してリクエストを処理するロジックが重要です。

同じ型に異なるシグネチャの複数のサブスクリプトを作成できますか?

はい。異なるパラメータのシグネチャでサブスクリプトをオーバーロードすることが許可されています:

struct Example { subscript(index: Int) -> Int { return index } subscript(key: String) -> String { return key.uppercased() } }

setなしで計算済みプロパティとしてサブスクリプトを使用することは許可されていますか?

はい、サブスクリプトは読み取り専用(get-only)であり、その場合、書き込みを試みるとコンパイルエラーが発生します。

struct ReadOnly { subscript(index: Int) -> Int { index * index } }

一般的なエラーとアンチパターン

  • インデックス範囲のチェックがない(Index out of range)
  • シングルリスポンシビリティの原則に違反する — サブスクリプトがビジネスロジックを持つ、ただのデータアクセスではない
  • あまりにも複雑で不明瞭なサブスクリプトのシグネチャ

実生活の例

ネガティブケース

大きな構造体が範囲チェックなしでサブスクリプトを実装しており、不正なインデックスによりアプリケーションがクラッシュします。

利点:

  • 迅速なプロトタイプ
  • コードが少ない

欠点:

  • ランタイムでのクラッシュの可能性が高い
  • 不明瞭なエラーによるデバッグの難しさ

ポジティブケース

Matrixはインデックスの範囲に関してpreconditionを実装しています。エラーはすぐにキャッチされ、プロダクションには入りません。

利点:

  • 入力の安全性
  • 診断とサポートが容易

欠点:

  • コードとチェックが少し増えますが、信頼性が向上します。