Swiftのsubscriptメカニズムは、2014年に言語と共に登場し、コレクションデータへのアクセスをより便利な構文で提供することを目的としています。Subscriptsを使用することで、配列、辞書、その他のコレクションの要素に角括弧を使ってアクセスすることが可能になります。現代のSwiftでは、独自の型のためにユーザー定義のsubscriptを作成でき、標準データ構造のようにAPIが直感的になります。
問題: 以前はアクセスするためのメソッドがより冗長に見え(例えば、.getElement(at:)を介して)、subscriptは型とのやりとりを簡潔にします。しかし、誤った実装は最適化されていないコードやコレクションの範囲外アクセスのエラーを引き起こす可能性があります。
解決策: subscriptを実装するためにsubscriptというキーワードを使用し、その後にパラメータと戻り値を指定します。Subscriptは読み取り専用または読み書き可能の両方として実装できます。さらに、異なるパラメータ用にoverloaded subscriptを作成することもできます。
コード例:
struct Matrix { let rows: Int let columns: Int var grid: [Double] init(rows: Int, columns: Int) { self.rows = rows self.columns = columns self.grid = Array(repeating: 0.0, count: rows * columns) } subscript(row: Int, column: Int) -> Double { get { assert(row >= 0 && row < rows && column >= 0 && column < columns, "Index out of range") return grid[(row * columns) + column] } set { assert(row >= 0 && row < rows && column >= 0 && column < columns, "Index out of range") grid[(row * columns) + column] = newValue } } } var matrix = Matrix(rows: 2, columns: 2) matrix[0, 1] = 3.14 print(matrix[0, 1]) // 3.14
主な特徴:
読み取り専用のsubscriptを指定できますか?それとも、subscriptは常にgetとsetを持つ必要がありますか?
subscriptはsetがない場合は読み取り専用(getのみ)であることができます。両方のアクセサを実装する必要はなく、これはプロパティにも似ています。
コード例:
subscript(index: Int) -> Int { get { return index * 2 } }
subscriptでinoutを介して可変パラメータを渡すことはできますか?
いいえ、subscriptはシグネチャ内でinoutパラメータをサポートしません。すべてのsubscriptパラメータは、アクセサ本体内でlet定数として受け取られます。
subscriptはオプショナル型を返すことができますか?
はい、subscriptはオプショナル値を返すことができ、たとえばコレクションの要素に安全にアクセスするために便利です。
コード例:
extension Array { subscript(safe index: Int) -> Element? { return indices.contains(index) ? self[index] : nil } }
複合型のmatrix用subscriptを範囲外チェックなしに実装すると、インデックスエラーによってアプリケーションがクラッシュします。
利点:
欠点:
安全なインデイジングとエラーハンドリングのためにオプショナルバージョンのsubscriptを追加し、APIが明示的で保護されます。
利点:
欠点: