2019-06-26
结构体是值类型, 而非引用类型。结构体无处不存在,许多Swift标准类型都是结构体,比如,Array, Int, Float, Double, Bool, Dictionary, Set 和 String都是被定义为结构体。所以它们所有自己的方法和属性。
struct Location {
let x: Int
let y: Int
}
let storeLocation = Location(x: 2, y: 4) // swift 自动提供的初始化函数,强制必须设置所有属性
struct DeliveryArea {
let center: Location // let 不可修改
var radius: Double // var 可修改
}
var storeArea = DeliveryArea(center: storeLocation, radius: 4) // var 可以修改其可修改属性
print(storeArea.radius) // 4.0
print(storeArea.center.x) // 2
storeArea.radius = 250
let fixedArea = DeliveryArea(center: storeLocation, radius: 4) // let 结构体属性不可修改
fixedArea.radius = 250 // Error: Cannot assign to property
// copy-on-assignment 结构体是值类型, 而非引用类型
var area1 = DeliveryArea(center: Location(x: 2, y: 4), radius: 2.5)
var area2 = area1
print(area1.radius) // 2.5
print(area2.radius) // 2.5
area1.radius = 4
print(area1.radius) // 4.0
print(area2.radius) // 2.5
struct Contact {
var fullName: String
var emailAddress: String
var relationship = "Friend" //默认属性
}
var person = Contact(fullName: "Grace Murray", emailAddress: "grace@navy.mil")
var person = Contact(
fullName: "Grace Murray",
emailAddress: "grace@navy.mil",
relationship: "Friend"
)
struct TV {
var height: Double
var width: Double
var diagonal: Int {
let result = (height * height + width * width).squareRoot().rounded()
return Int(result)
}
}
var tv = TV(height: 53.93, width: 95.87)
let size = tv.diagonal // 110
tv.width = tv.height
let diagonal = tv.diagonal // 76
var diagonal: Int {
get {
let result = (height * height + width * width).squareRoot().rounded()
return Int(result)
}
set {
let ratioWidth = 16.0
let ratioHeight = 9.0
let ratioDiagonal = (ratioWidth * ratioWidth + ratioHeight * ratioHeight).squareRoot()
height = Double(newValue) * ratioHeight / ratioDiagonal
width = height * ratioWidth / ratioHeight
}
}
tv.diagonal = 70
let height = tv.height // 34.32...
let width = tv.width // 61.01...
类型属性,跨越实例共享
struct Level {
static var highestLevel = 1 // static 修饰为 type properties
let id: Int
var boss: String
var unlocked: Bool
}
let highestLevel = level3.highestLevel // Error: you can't access a type property on an instance
let highestLevel = Level.highestLevel // 1
willSet, didSet 仅用于存储属性,计算属性直接使用 getter 和 setter 即可。
willSet, didSet 在结构体初始化时不会被调用,只有属性更新新值时才会调用。
struct Level {
static var highestLevel = 1
let id: Int
var boss: String
var unlocked: Bool {
didSet { // obsevers
if unlocked && id > Level.highestLevel {
Level.highestLevel = id
}
}
}
}
struct LightBulb {
static let maxCurrent = 40
var current = 0 {
didSet {
if current > LightBulb.maxCurrent {
print("""
Current is too high,
falling back to previous setting.
"""
)
current = oldValue
}
}
}
}
var light = LightBulb()
light.current = 50
var current = light.current // 0
light.current = 40
current = light.current // 40
struct Circle {
lazy var pi = { // lazy 属性必须是变量 (var)
return ((4.0 * atan(1.0 / 5.0)) - atan(1.0 / 239.0)) * 4.0
}()
var radius = 0.0
var circumference: Double {
mutating get {
return pi * radius * 2
}
}
init(radius: Double) { // 自定义初始化函数,一旦自定义构造方法,默认构造方法将无效
self.radius = radius
}
}
var circle = Circle(radius: 5) // got a circle, pi has not been run
let circumference = circle.circumference // 31.42 // also, pi now has a value
func distance(from source: (x: Int, y: Int), to target: (x: Int, y: Int)) -> Double {
let distanceX = Double(source.x - target.x)
let distanceY = Double(source.y - target.y)
return (distanceX * distanceX + distanceY * distanceY).squareRoot()
}
struct DeliveryArea {
let center: Location
var radius: Double
func contains(_ location: Location) -> Bool { // Method
let distanceFromCenter =
distance(from: (center.x, center.y), to: (location.x, location.y))
return distanceFromCenter < radius
}
}
let area = DeliveryArea(center: Location(x: 5, y: 5), radius: 4.5)
let customerLocation = Location(x: 2, y: 2)
area.contains(customerLocation) // true
let months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]
struct SimpleDate {
var month: String
var day: Int
func monthsUntilWinterBreak() -> Int {
return months.index(of: "December")! - months.index(of: self.month)! // self
// return months.index(of: "December")! - months.index(of: month)! // self 可省略
}
}
date.monthsUntilWinterBreak() // 2
let date = SimpleDate(month: "January", day: 14) //swift 自动提供的初始化函数,强制必须设置所有属性
let date = SimpleDate(day: 14) // Error!
struct SimpleDate {
var month: String
var day: Int
init(day: Int) { // 自定义初始化函数
month = "January"
self.day = day // 都为 "day",self 不可省
}
func monthsUntilWinterBreak() -> Int {
return months.index(of: "December")! months.index(of: month)!
}
}
let date = SimpleDate(day: 14)
date.month // January
date.monthsUntilWinterBreak() // 11
let date = SimpleDate(month: "February", day: 14) // Error! // 一旦自定义构造方法,默认构造方法将无效
结构体为值类型, 如果一个方法改变了其属性值, 其实例的值须修改。
所以有 mutating 方法的结构体不能实例化为常量。
用 mutating 修饰的方法, swift 传入的 self 为一个标记为 inout 的参数。
struct SimpleDate {
var month: String
var day: Int
init(day: Int) {
month = "January"
self.day = day
}
mutating func advance() { // 只有标记了 mutating 的方法才能修改结构体实例的值
day += 1
}
func monthsUntilWinterBreak() -> Int {
return months.index(of: "December")! months.index(of: month)!
}
}
类型方法,跨越实例共享
struct Math { // 可用于 namespace (命名空间)
static func factorial(of number: Int) -> Int {
return (1...number).reduce(1, *)
}
}
Math.factorial(of: 6) // 720
public protocol CustomStringConvertible {
/// A textual representation of this instance.
public var description: String { get }
}
struct DeliveryArea: CustomStringConvertible {
let center: Location
var radius: Double
var description: String { // 实现协议必须实现其方法
return """
Area with center: x: \(center.x) - y: \(center.y),
radius: \(radius)
"""
}
func contains(_ location: Location) -> Bool { // Method
let distanceFromCenter =
distance(from: (center.x, center.y), to: (location.x, location.y))
return distanceFromCenter < radius
}
}
// print() 调用 description 方法进行输出
print(area1) // Area with center: x: 2 - y: 4, radius: 4.0
print(area2) // Area with center: x: 2 - y: 4, radius: 2.5
struct Math {
static func factorial(of number: Int) -> Int {
return (1...number).reduce(1, *)
}
}
extension Math {
static func primeFactors(of value: Int) -> [Int] {
var remainingValue = value
var testFactor = 2
var primes: [Int] = []
while testFactor * testFactor <= remainingValue {
if remainingValue % testFactor == 0 {
primes.append(testFactor) remainingValue /= testFactor
} else {
testFactor += 1
}
}
if remainingValue > 1 {
primes.append(remainingValue)
}
return primes
}
}
Math.primeFactors(of: 81) // [3, 3, 3, 3]
在 Extension 中添加初始化方法,其结构体自动生成的初始化方法将会保留
struct SimpleDate {
var month: String
var day: Int
func monthsUntilWinterBreak() -> Int {
return months.index(of: "December")! - months.index(of: month)!
}
mutating func advance() {
day += 1
}
}
extension SimpleDate {
init() {
month = "January"
day = 1
}
}
类为引用类型
class Person {
var firstName: String
var lastName: String
init(firstName: String, lastName: String) {
self.firstName = firstName
self.lastName = lastName
}
var fullName: String {
return "\(firstName) \(lastName)"
}
}
let john = Person(firstName: "Johnny", lastName: "Appleseed")
var homeOwner = john
john.firstName = "John" // John wants to use his short name!
john.firstName // "John"
homeOwner.firstName // "John"
struct Grade {
let letter: String
let points: Double
let credits: Double
}
class Student {
var firstName: String
var lastName: String
var credits = 0.0
var grades: [Grade] = []
init(firstName: String, lastName: String) {
self.firstName = firstName
self.lastName = lastName
}
func recordGrade(_ grade: Grade) {
grades.append(grade)
credits += grade.credits
}
}
let jane = Student(firstName: "Jane", lastName: "Appleseed")
let history = Grade(letter: "B", points: 9.0, credits: 3.0)
var math = Grade(letter: "A", points: 16.0, credits: 4.0)
jane.recordGrade(history)
jane.recordGrade(math)
jane = Student(firstName: "John", lastName: "Appleseed") // Error: jane is a `let` constant
jane.credits // 7
// The teacher made a mistake; math has 5 credits
math = Grade(letter: "A", points: 20.0, credits: 5.0)
jane.recordGrade(math)
jane.credits // 12, not 8!
extension Student {
var fullName: String {
return "\(firstName) \(lastName)"
}
}
struct Grade {
var letter: Character
var points: Double
var credits: Double
}
class Person {
var firstName: String
var lastName: String
init(firstName: String, lastName: String) {
self.firstName = firstName
self.lastName = lastName
}
}
class Student: Person {
var grades: [Grade] = []
func recordGrade(_ grade: Grade) {
grades.append(grade)
}
}
let john = Person(firstName: "Johnny", lastName: "Appleseed")
let jane = Student(firstName: "Jane", lastName: "Appleseed")
john.firstName // "John"
jane.firstName // "Jane"
let history = Grade(letter: "B", points: 9.0, credits: 3.0)
jane.recordGrade(history)
// john.recordGrade(history) // john is not a student!
class BandMember: Student {
var minimumPracticeTime = 2
}
class OboePlayer: BandMember {
override var minimumPracticeTime: Int { // 重写
get {
return super.minimumPracticeTime * 2
}
set {
super.minimumPracticeTime = newValue / 2
}
}
}
final class FinalStudent: Person {}
class FinalStudentAthlete: FinalStudent {} // Build error!
class AnotherStudent: Person {
final func recordGrade(_ grade: Grade) {}
}
class AnotherStudentAthlete: AnotherStudent {
override func recordGrade(_ grade: Grade) {} // Build error!
}
func phonebookName(_ person: Person) -> String {
return "\(person.lastName), \(person.firstName)"
}
let person = Person(firstName: "Johnny", lastName: "Appleseed")
let oboePlayer = OboePlayer(firstName: "Jane", lastName: "Appleseed")
phonebookName(person) // Appleseed, Johnny
phonebookName(oboePlayer) // Appleseed, Jane
var hallMonitor = Student(firstName: "Jill", lastName: "Bananapeel")
hallMonitor = oboePlayer
oboePlayer as Student // 子类转为父类, 编译时期便可确定其正确性
(oboePlayer as Student).minimumPracticeTime // ERROR: 不再是 BandMember, 不能访问其属性
hallMonitor as? BandMember // 父类转子类, 为 Optional, 如果转换失败则为 nil
(hallMonitor as? BandMember)?.minimumPracticeTime // 4 (optional)
hallMonitor as! BandMember // 强制转换, 如果失败, 程序将崩溃
(hallMonitor as! BandMember).minimumPracticeTime // 4 (force unwrapped)
if let hallMonitor = hallMonitor as? BandMember { // 使用 if let
print("This hall monitor is a band member and practices at least \(hallMonitor.minimumPracticeTime) hours per week.")
}
子类转为父类的使用场景
func afterClassActivity(for student: Student) -> String {
return "Goes home!"
}
func afterClassActivity(for student: BandMember) -> String {
return "Goes to practice!"
}
// Swift’s dispatch rules: 调用类型最精确匹配的方法
afterClassActivity(for: oboePlayer) // Goes to practice!
afterClassActivity(for: oboePlayer as Student) // Goes home!
class StudentAthlete: Student {
var failedClasses: [Grade] = []
override func recordGrade(_ grade: Grade) { // 重写方法,必须要用 Override 修饰
super.recordGrade(grade) // super 调用父类方法
if grade.letter == "F" {
failedClasses.append(grade)
}
}
var isEligible: Bool {
return failedClasses.count < 3
}
}
class StudentAthlete: Student {
var sports: [String]
init(sports: [String]) {
self.sports = sports
// Build error - super.init isn’t called before
// returning from initializer
}
}
class StudentAthlete: Student {
var sports: [String]
init(firstName: String, lastName: String, sports: [String]) {
self.sports = sports
super.init(firstName: firstName, lastName: lastName)
}
}
class StudentAthlete: Student {
var sports: [String]
init(firstName: String, lastName: String, sports: [String]) {
self.sports = sports // phase 1
let passGrade = Grade(letter: "P", points: 0.0, credits: 0.0) // 可以创建局部属性,但不能调用属性和方法
super.init(firstName: firstName, lastName: lastName) // 完成后进入 phase 2
recordGrade(passGrade) // phase 2, 可以使用属性和方法以及 self
}
}
class Student {
let firstName: String
let lastName: String
var grades: [Grade] = []
required init(firstName: String, lastName: String) { // 强制所有子类必须重写
self.firstName = firstName
self.lastName = lastName
}
init(transfer: Student) {
self.firstName = transfer.firstName
self.lastName = transfer.lastName
}
func recordGrade(_ grade: Grade) {
grades.append(grade)
}
}
class StudentAthlete: Student {
// Now required by the compiler!
required init(firstName: String, lastName: String) { // 有 required 修饰,Override 可省略
self.sports = []
super.init(firstName: firstName, lastName: lastName)
}
...
}
class Student {
let firstName: String
let lastName: String
var grades: [Grade] = []
required init(firstName: String, lastName: String) {
self.firstName = firstName
self.lastName = lastName
}
convenience init(transfer: Student) { // convenience 强制直接或间接调用其他 non-convenience initializer
self.init(firstName: transfer.firstName, lastName: transfer.lastName)
}
func recordGrade(_ grade: Grade) {
grades.append(grade)
}
}
class Person {
...
deinit {
print("\(firstName) \(lastName) is being removed from memory!")
}
}
automatic reference counting (ARC)
Swift 编译器在编译期间会自动添加增减引用计数的方法调用
var someone = Person(firstName: "Johnny", lastName: "Appleseed")
// Person object has a reference count of 1 (someone variable)
var anotherSomeone: Person? = someone
// Reference count 2 (someone, anotherSomeone)
var lotsOfPeople = [someone, someone, anotherSomeone, someone]
// Reference count 6 (someone, anotherSomeone, 4 references in lotsOfPeople)
anotherSomeone = nil
// Reference count 5 (someone, 4 references in lotsOfPeople)
lotsOfPeople = []
// Reference count 1 (someone)
someone = Person(firstName: "Johnny", lastName: "Appleseed")
// Reference count 0 for the original Person object!
// Variable someone now references a new object
class Student: Person {
var partner: Student?
...
deinit {
print("\(firstName) is being deallocated!") }
}
var alice: Student? = Student(firstName: "Alice", lastName: "Appleseed")
var bob: Student? = Student(firstName: "Bob", lastName: "Appleseed")
alice?.partner = bob
bob?.partner = alice
alice = nil
bob = nil
// deinit 并没有调用
class Student: Person {
weak var partner: Student?
...
}
enum Month {
case january
case february
case march
case april
case may
case june
case july
case august
case september
case october
case november
case december
}
// 等价于
enum Month {
case january, february, march, april, may, june, july, august, september, october, november, december
}
func semester(for month: Month) -> String {
switch month {
case Month.august, Month.september, Month.october, Month.november, Month.december:
return "Autumn"
case Month.january, Month.february, Month.march, Month.april, Month.may:
return "Spring"
default:
return "Not in the school year"
}
}
// 等价于
func semester(for month: Month) -> String {
switch month {
case .august, .september, .october, .november, .december:
return "Autumn"
case .january, .february, .march, .april, .may:
return "Spring"
default:
return "Not in the school year"
}
}
var month = Month.april
semester(for: month) // "Spring"
month = .september
semester(for: month) // "Autumn"
func semester(for month: Month) -> String {
switch month {
case .august, .september, .october, .november, .december:
return "Autumn"
case .january, .february, .march, .april, .may:
return "Spring"
case .june, .july:
return "Summer"
}
}
enum Month: Int { // 指定为 Int, 也可以是 String, Float, Character 等
// january 为 0, 其他依次递增
case january, february, march, april, may, june, july, august, september, october, november, december
}
enum Month: Int {
// 指定 january 为 1, 其他依次递增
case january=1, february, march, april, may, june, july, august, september, october, november, december
}
enum Coin: Int {
case penny = 1
case nickel = 5
case dime = 10
case quarter = 25
}
let coin = Coin.quarter
coin.rawValue // 25
访问 Raw value
func monthsUntilWinterBreak(from month: Month) -> Int {
return Month.december.rawValue - month.rawValue // 访问 Raw value
}
monthsUntilWinterBreak(from: .april) // 8
用 Raw value 初始化枚举
let fifthMonth = Month(rawValue: 5) // 不能保证存在此 rawValue 的枚举,故返回 optional
monthsUntilWinterBreak(from: fifthMonth) // Error: not unwrapped
let fifthMonth = Month(rawValue: 5)!
monthsUntilWinterBreak(from: fifthMonth) // 7
enum Icon: String { // 指定为 String
// 如果不指定,默认自动为与枚举项名称相同的字符串
case music
case sports
case weather
var filename: String {
return "\(rawValue).png"
}
}
let icon = Icon.weather
icon.filename // weather.png
var balance = 100
enum WithdrawalResult {
case Success(Int)
case Error(String)
}
func withdraw(amount: Int) -> WithdrawalResult {
if amount <= balance {
balance -= amount
return .Success(balance)
} else {
return .Error("Not enough money!")
}
}
let result = withdraw(99)
switch result {
case let .Success(newBalance):
print("Your new balance is: \(newBalance)")
case let .Error(message):
print(message)
}
// Your new balance is: 1
与 if case 或 guard case 一起使用
enum HTTPMethod {
case GET
case POST(String)
}
let request = HTTPMethod.post(body: "Hi there")
guard case .post(let body) = request else { // guard case, 是否 request 包含 post 枚举项, 包含则绑定关联值
fatalError("No message was posted")
}
print(body) // 打印关联值
枚举可以用作 状态机 ( state machine )
enum TrafficLight {
case Red, Yellow, Green
}
let trafficLight = TrafficLight.Red
enum Pet: CaseIterable {
case cat, dog, bird, turtle, fish, hamster
}
for pet in Pet.allCases {
print(pet)
}
enum Math {
static func factorial(of number: Int) -> Int {
return (1...number).reduce(1, *)
}
}
let factorial = Math.factorial(of: 6) // 720
let math = Math() // ERROR: No accessible initializers
Optionals 就是用关联值的枚举
var age: Int?
age = 17
age = nil
switch age {
case .none:
print("No value")
case .some(let value):
print("Got a value: \(value)")
}
let optionalNil: Int? = .none
optionalNil == nil // true
optionalNil == .none // true
protocol Vehicle {
func accelerate()
func stop()
}
class Unicycle: Vehicle { //实现 Vehicle 协议,必须实现其所有方法
var peddling = false
func accelerate() {
peddling = true
}
func stop() {
peddling = false
}
}
enum Direction {
case left
case right
}
protocol DirectionalVehicle {
func accelerate()
func stop()
func turn(_ direction: Direction)
func description() -> String
}
协议 Methods 不能有任何有关实现的代码,包括默认参数
protocol OptionalDirectionVehicle {
// Build error!
func turn(_ direction: Direction = .left)
}
// 需要用重载实现
protocol OptionalDirectionVehicle {
func turn()
func turn(_ direction: Direction)
}
protocol VehicleProperties {
var weight: Int { get }
var name: String { get set }
}
protocol Account {
var value: Double { get set }
init(initialAmount: Double)
init?(transferAccount: Account)
}
class BitcoinAccount: Account {
var value: Double
required init(initialAmount: Double) {
value = initialAmount
}
required init?(transferAccount: Account) {
guard transferAccount.value > 0.0 else {
return nil
}
value = transferAccount.value
}
}
var accountType: Account.Type = BitcoinAccount.self
let account = accountType.init(initialAmount: 30.00)
let transferAccount = accountType.init(transferAccount: account)!
protocol WheeledVehicle: Vehicle {
var numberOfWheels: Int { get }
var wheelSize: Double { get set }
}
class Bike: Vehicle {
var peddling = false
var brakesApplied = false
func accelerate() {
peddling = true
brakesApplied = false
}
func stop() {
peddling = false
brakesApplied = true
}
}
实现 { get } 的属性
实现 { get set } 的属性
class Bike: WheeledVehicle {
// 实现属性
let numberOfWheels = 2
var wheelSize = 16.0
var peddling = false
var brakesApplied = false
func accelerate() {
peddling = true
brakesApplied = false
}
func stop() {
peddling = false
brakesApplied = true
}
}
protocol WeightCalculatable {
associatedtype WeightType
var weight: WeightType { get }
}
class HeavyThing: WeightCalculatable {
// This heavy thing only needs integer accuracy
typealias WeightType = Int // 由于类型推导,可省略
var weight: Int {
return 100
}
}
class LightThing: WeightCalculatable {
// This light thing needs decimal places
typealias WeightType = Double // 由于类型推导,可省略
var weight: Double {
return 0.0025
}
}
// 因为 associatedtype 没有确定,WeightCalculatable 不能用于变量声明
let weightedThing: WeightCalculatable = LightThing() // Build error!
protocol Wheeled {
var numberOfWheels: Int { get }
var wheelSize: Double { get set }
}
class Bike: Vehicle, Wheeled {
// Implement both Vehicle and Wheeled
}
func roundAndRound(transportation: Vehicle & Wheeled) { // 类型需要同时实现 Vehicle 和 Wheeled 协议
transportation.stop()
print("The brakes are being applied to \(transportation.numberOfWheels) wheels.")
}
roundAndRound(transportation: Bike()) // The brakes are being applied to 2 wheels.
可以扩展 swift 标准库里的类型来实现协议
protocol Reflective {
var typeName: String { get }
}
extension String: Reflective {
var typeName: String {
return "I'm a String"
}
}
let title = "Swift Apprentice!"
title.typeName // I'm a String
class AnotherBike: Wheeled {
var peddling = false
let numberOfWheels = 2
var wheelSize = 16.0
}
extension AnotherBike: Vehicle {
func accelerate() {
peddling = true
}
func stop() {
peddling = false
}
}
protocol Named {
var name: String { get set }
}
class ClassyName: Named {
var name: String
init(name: String) {
self.name = name
}
}
struct StructyName: Named {
var name: String
}
// 引用类型
var named: Named = ClassyName(name: "Classy")
var copy = named
named.name = "Still Classy"
named.name // Still Classy
copy.name // Still Classy
// 值类型
named = StructyName(name: "Structy")
copy = named
named.name = "Still Structy?"
named.name // Still Structy?
copy.name // Structy
// 指定实现类型必须为 class,此时协议类型确定为引用类型
protocol Named: class {
var name: String { get set }
}
protocol Equatable {
static func ==(lhs: Self, rhs: Self) -> Bool
}
class Record {
var wins: Int
var losses: Int
init(wins: Int, losses: Int) {
self.wins = wins
self.losses = losses
}
}
let recordA = Record(wins: 10, losses: 5)
let recordB = Record(wins: 10, losses: 5)
recordA == recordB // Build error!
extension Record: Equatable {
static func ==(lhs: Record, rhs: Record) -> Bool {
return lhs.wins == rhs.wins && lhs.losses == rhs.losses
}
}
recordA == recordB // true
protocol Comparable: Equatable {
static func <(lhs: Self, rhs: Self) -> Bool
static func <=(lhs: Self, rhs: Self) -> Bool
static func >=(lhs: Self, rhs: Self) -> Bool
static func >(lhs: Self, rhs: Self) -> Bool
}
extension Record: Comparable {
static func <(lhs: Record, rhs: Record) -> Bool {
if lhs.wins == rhs.wins {
return lhs.losses > rhs.losses
}
return lhs.wins < rhs.wins
}
}
// 实现了 Equatable 和 Comparable 就可以解锁很方法,如: sort, max, min, starts, contains 等
let teamA = Record(wins: 14, losses: 11)
let teamB = Record(wins: 23, losses: 8)
let teamC = Record(wins: 23, losses: 9)
var leagueRecords = [teamA, teamB, teamC]
leagueRecords.sort()
// {wins 14, losses 11}
// {wins 23, losses 9}
// {wins 23, losses 8}
leagueRecords.max() // {wins 23, losses 8}
leagueRecords.min() // {wins 14, losses 11}
leagueRecords.starts(with: [teamA, teamC]) // true
leagueRecords.contains(teamA) // true
class Student {
let email: String
let firstName: String
let lastName: String
init(email: String, firstName: String, lastName: String) {
self.email = email
self.firstName = firstName
self.lastName = lastName
}
}
extension Student: Hashable {
static func ==(lhs: Student, rhs: Student) -> Bool {
return lhs.email == rhs.email &&
lhs.firstName == rhs.firstName &&
lhs.lastName == rhs.lastName
}
func hash(into hasher: inout Hasher) {
hasher.combine(email)
hasher.combine(firstName)
hasher.combine(lastName)
}
}
let john = Student(email: "johnny.appleseed@apple.com", firstName: "Johnny", lastName: "Appleseed")
let lockerMap = [john: "14B"]
protocol CustomStringConvertible {
var description: String { get }
}
print(john) // Student
extension Student: CustomStringConvertible {
var description: String {
return "\(firstName) \(lastName)"
}
}
print(john) // Johnny Appleseed
enum PetKind {
case cat
case dog
}
struct KeeperKind {
var keeperOf: PetKind
}
let catKeeper = KeeperKind(keeperOf: .cat)
let dogKeeper = KeeperKind(keeperOf: .dog)
class Cat {}
class Dog {}
class Keeper<Animal> {}
var aCatKeeper = Keeper<Cat>()
var aDogKeeper = Keeper<Dog>()
var aKeeper = Keeper() // compile-time error!
class Cat {
var name: String
init(name: String) {
self.name = name
}
}
class Dog {
var name: String
init(name: String) {
self.name = name
}
}
class Keeper<Animal> {
var name: String
var morningCare: Animal
var afternoonCare: Animal
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"))
protocol Pet {
var name: String { get }
}
extension Cat: Pet {}
extension Dog: Pet {}
class Keeper<Animal: Pet> {
...
}
extension Array where Element: Cat {
func meow() {
forEach {
print("\($0.name) says meow!")
}
}
}
protocol Meowable {
func meow()
}
extension Cat: Meowable {
func meow() {
print("\(self.name) says meow!")
}
}
extension Array: Meowable where Element: Meowable {
func meow() {
forEach { $0.meow() }
}
}
let animalAges: [Int] = [2,5,7,9]
// 等价于
let animalAges: Array<Int> = [2,5,7,9]
let array = [Int]()
// 等价于
let array = Array<Int>()
struct Dictionary<Key: Hashable, Value>
let intNames: Dictionary<Int, String> = [42: "forty-two"]
let intNames2: [Int: String] = [42: "forty-two", 7: "seven"]
let intNames3 = [42: "forty-two", 7: "seven"] // 类型推导
enum OptionalDate {
case none
case some(Date)
}
enum OptionalString {
case none
case some(String)
}
struct FormResults {
// other properties here
var birthday: OptionalDate
var lastName: OptionalString
}
enum Optional<Wrapped> { // swift 内部 Optional 的近似实现
case none
case some(Wrapped)
}
var birthdate: Optional<Date> = .none
if birthdate == .none {
// no birthdate
}
var birthdate: Date? = nil
if birthdate == nil {
// no birthdate
}
func swapped<T, U>(_ x: T, _ y: U) -> (U, T) {
return (y, x)
}
swapped(33, "Jay")
// returns ("Jay", 33)