Swift – Subscripts

Známe z Objective-C jako array[index]  nebo dict[key] . Swift jde opět dál a umožňuje používat subscripts nejen u tříd, ale také u výčtů a struktur.

Syntax je takový mix instančních metod a computed properties. Vezmeme si rovnou ukázku z knížky.

class TimesTable {
  let multiplier: Int!

  init( multiplier: Int ) {
    self.multiplier = multiplier
  }

  subscript( index: Int ) -> Int {
    return index * self.multiplier
  }
}

let tt = TimesTable( multiplier: 10 )

tt[0]    //  0 * 10 ==   0
tt[1]    //  1 * 10 ==  10
tt[20]   // 20 * 10 == 200

Třída TimeTables  má inicializátor s parametrem multiplier , který budeme používat v našem subscriptu pro násobení. Náš subscript má jeden vstupní parametr s názvem index  a vrací výsledek násobení index * multiplier .

That’s it. Vidíte, že syntax se podobá instanční metodě. Vstup je Int  a výstup je Int . Dál to pokračuje stejně jako computed properties. Je to read only a tak můžeme v klidu vypustit get .

Subscript může mít jakékoli množství vstupních parametrů a podporuje i variadické parametry. Nelze používat inout  parametry a nelze u parametrů nastavit výchozí hodnotu. Vracet může jakoukoli hodnotu.

Subscriptů může být u jedné třídy více a kdo by to hledal, říká se tomu subscript overloading.

Teď složitější příklad na kterém uvidíte vše potřebné.

class IntMatrix {
  let numberOfRows: Int
  let numberOfColumns: Int

  let rows: Array< Array< Int > >

  init( rows: Int, columns: Int ) {
    assert( rows > 0, "Number of rows must be > 0" )
    assert( columns > 0, "Number of columns must be > 0" )

    self.numberOfRows = rows
    self.numberOfColumns = columns

    var rows = Array< Array< Int > >()

    var emptyRow = Array( count: self.numberOfColumns, repeatedValue: 0 )
    for _ in 1...self.numberOfColumns {
      var row = emptyRow
      row.unshare()
      rows.append( row )
    }

    self.rows = rows
  }

  subscript( rowIndex: Int ) -> Array< Int > {
    assert( self.indexIsValidForRow( rowIndex ), "Invalid row index" )

    return self.rows[ rowIndex ]
  }

  subscript( rowIndex: Int, columnIndex: Int ) -> Int {
    get {
      assert( self.indexIsValidForRow( rowIndex ), "Invalid row index" )
      assert( self.indexIsValidForColumn( columnIndex ), "Invalid column index" )

      return self.rows[ rowIndex ][ columnIndex ]
    }
    set {
      assert( self.indexIsValidForRow( rowIndex ), "Invalid row index" )
      assert( self.indexIsValidForColumn( columnIndex ), "Invalid column index" )

      self.rows[ rowIndex ][ columnIndex ] = newValue
    }
  }

  func indexIsValidForRow( rowIndex: Int ) -> Bool {
    return ( rowIndex >= 0 && rowIndex < self.numberOfRows )
  }

  func indexIsValidForColumn( columnIndex: Int ) -> Bool {
    return ( columnIndex >= 0 && columnIndex < self.numberOfColumns )
  }
}

let matrix = IntMatrix( rows: 10, columns: 5 )
matrix[0]          // [0, 0, 0, 0, 0]
matrix[0, 0]       // 0
matrix[0, 0] = 10
matrix[0]          // [10, 0, 0, 0, 0]
matrix[0, 0]       // 10
matrix[1]          // [0, 0, 0, 0, 0]

Dneska to bylo kratší. Víc k tomu není co dodat. Teď už toho umíme poměrně dost, tak se příště mrknem na dědičnost.