Chapter 17: Generics

大綱

Values defined by other values

  • 什麼情況下最適合使用Generics ?

    • set of possible PetKind values defines the set of possible KeeperKind values

// 每當enum增加一個case
enum PetKind {
  case cat
  case dog
}
// KeeperKind就多一種value可以選擇
struct KeeperKind {
  var keeperOf: PetKind
}

let catKeeper = KeeperKind(keeperOf: .cat)
let dogKeeper = KeeperKind(keeperOf: .dog)

Types defined by other types

// 增加class
class Cat {}
class Dog {}
// 增加對應的class case
class KeeperForCats {}
class KeeperForDogs {}

Anatomy of generic types

  • you can define a generic type for keepers

    • That Animal in angle brackets is the type parameter that specifies the type for the kind of animal you’re keeping.

    • you’ll encounter names like T (short for Type) from time to time, but these names should be avoided when the type parameter has a clear role such as Animal

class Keeper<Animal> {}

var aCatKeeper = Keeper<Cat>()
var aKeeper = Keeper()  // compile-time error!”

Using type parameters

  • you can use type parameters such as Animal throughout your type definitions

class Cat {
  var name: String

  init(name: String) {
    self.name = name
  }
}

class Dog {
  var name: String

  init(name: String) {
    self.name = name
  }
}

// 宣告Animal是一種generic type
class Keeper<Animal> {
  var name: String
  var morningCare: Animal
  var afternoonCare: Animal

  // 利用type parameters來當作init的parameter
  init(name: String, morningCare: Animal, afternoonCare: Animal) {
    self.name = name
    self.morningCare = morningCare
    self.afternoonCare = afternoonCare
  }
}

let jason = Keeper(name: "Jason", morningCare: Cat(name: "Whiskers"), afternoonCare: Cat(name: "Sleepy"))

Type constraints

  • the identifier Animal serves as a type parameter, which is a named placeholder for some actual type that will be supplied later.

  • In Swift, you do this with various kinds of type constraints.

    // 對generic type (Animal)進行type constraints進行限制為Pet type
    class Keeper<Animal: Pet> {}
    
    // 利用where關鍵字來找Array中所有generic type中是Cat type
    extension Array where Element: Cat {
      func meow() {
        forEach { print("\($0.name) says meow!") }
      }
    }

Arrays

  • Array and [Element] are exactly interchangeable. So you could even call an array’s default initializer by writing Int instead of Array().

let animalAges: [Int] = [2,5,7,9]
let animalAges: Array<Int> = [2,5,7,9]

Dictionaries

  • To instantiate types such as Dictionary with multiple type parameters, simply provide a comma-separated type argument list:

let intNames: Dictionary<Int, String> = [42: "forty-two"]
let intNames2: [Int: String] = [42: "forty-two", 7: "seven"]
let intNames3 = [42: "forty-two", 7: "seven"]

Optionals

  • 自定義optional type

// 自定義optional type
enum OptionalDate {
  case none
  case some(Date)
}

// 自定義optional type
enum OptionalString {
  case none
  case some(String)
}

struct FormResults {
  // other properties here
  var birthday: OptionalDate
  var lastName: OptionalString
}

// 判斷自己自定義的option type
var birthdate: Optional<Date> = .none
if birthdate == .none {
  // no birthdate
}

// 比較常使用的判斷方式
var birthdate2: Date? = nil
if birthdate2 == nil {
  // no birthdate
}

Generic function parameters

  • “A function's type parameter list comes after the function name. You can then use the generic parameters in the rest of the definition.”

// <T, U>就是此function的 type parameter list
func swapped<T, U>(_ x: T, _ y: U) -> (U, T) {
  return (y, x)
}

swapped(33, "Jay")  // returns ("Jay", 33)

Key points

  • Generics are everywhere in Swift: in optionals, arrays, dictionaries, other collection structures, and most basic operators like + and ==.

  • Generics express systematic variation at the level of types via type parameters that range over possible concrete types.

  • Generics are like functions for the compiler. They are evaluated at compile time and result in new types which are specializations of the generic type.

  • A generic type is not a real type on its own, but more like a recipe, program, or template for defining new types.

  • Swift provides a rich system of type constraints, which lets you specify what types are allowed for various type parameters.

Last updated

Was this helpful?