Swift学习-基础01

2022-05-26  本文已影响0人  会跑的鱼_09
1.可选类型

Swift 的可选(Optional)类型,用于处理值缺失的情况。可选表示"那儿有一个值,并且它等于 x "或者"那儿没有值"。

//声明可选择类型,2种方式一样
var optionalInteger: Int?
var optionalInteger: Optional<Int>

//强制解析
var myString: String?
myString = "hello swift"
if myString != nil {
  print(myString!)
}

//自动解析
var myString: String!
myString = "hello swift"
if myString != nil {
  print(myString) //不需要!号
}

//可选绑定
//使用可选绑定(optional binding)来判断可选类型是否包含值,如果包含就把值赋给一个临时常量或者变量。可选绑定可以用在if和while语句中来对可选类型的值进行判断并把值赋给一个常量或者变量
if let constantName = someOptional {
    statements
}

var myString: String?
myString = "hello swift"
if let str = myString {
  print(str)
}
2.swift字符串

Swift 字符串是一系列字符的集合。例如 "Hello, World!" 这样的有序的字符类型的值的集合,它的数据类型为 String

//创建字符串
//使用字面量
var stringA = "hello, world"
print(stringA)
//String实例化
var stringB = String("hello world")
print(stringB)

//字符串中插入值:使用\(var)来插入变量或常量
var varA = 20
let constA = 100
var stringA = "\(varA) 加 \(constA) 等于 \(varA + constA)"
print(stringA)

//字符串连接:直接使用+号来连接
let constA = "hello"
let constB = "world"
var stringA = constA + constB
print(stringA)

//字符串比较:使用==来比较2个字符串是否相等
var varA = "hello world"
var varB = "hello world"
if varA == varB {
  print("相等")
}

//字符串遍历
let str = "菜鸟教程runoob.com"

print("---- 正序遍历 ----")
var i = 0
for ch in str {
    print("\(i): \(ch)")
    i += 1
}

print("---- 逆序遍历 ----")
var j = str.count
for ch in str.reversed() {
    j -= 1
    print("\(j): \(ch)")
}

print("---- 基于索引的正序遍历 ----")
for i in 0..<str.count {
    let ch: Character = str[str.index(str.startIndex, offsetBy: i)]
    print("\(i): \(ch)")
}

print("---- 基于索引的逆序遍历 ----")
//for i in stride(from: str.count - 1, to: -1, by: -1) {
for i in stride(from: str.count - 1, through: 0, by: -1) {
    let ch: Character = str[str.index(str.startIndex, offsetBy: i)]
    print("\(i): \(ch)")
}

print("---- 基于EnumeratedSequence的遍历 ----")
for (i, ch) in str.enumerated() {
    print("\(i): \(ch)")
}
3.数组

Swift 数组使用有序列表存储同一类型的多个值。相同的值可以多次出现在一个数组的不同位置中。如果创建一个数组,并赋值给一个变量,则创建的集合就是可以修改的。如果将一个数组赋值给常量,数组就不可更改

//创建数组
var array: [Int] = [] //推荐这种方式
var array1 = [Int]()
var array2 = [Int](repeating: 0, count: 5)
var array3: [Int] = [10, 20, 30] 
var array4 = [10, 20, 30]

//访问数组
var someInts = [Int](repeating: 10, count: 3)
var someVar = someInts[0]
print("第0个元素\(someVar)")

//修改数组:你可以使用 append() 方法或者赋值运算符 += 在数组末尾添加元素,如下所示,我们初始化一个数组,并向其添加元素
var someInts = [Int]()

someInts.append(20)
someInts.append(30)
someInts += [40]
var someVar = someInts[0]
print( "第一个元素的值 \(someVar)" )
//通过索引修改数组元素的值
someInts[2] = 50
print( "第三个元素的值 \(someInts[2])" )

//遍历数组
var someStrs = [String]()

someStrs.append("Apple")
someStrs.append("Amazon")
someStrs.append("Runoob")
someStrs += ["Google"]

for item in someStrs {
   print(item)
}

//如果我们同时需要每个数据项的值和索引值,可以使用 String 的 enumerate() 方法来进行数组遍历
var someStrs = [String]()

someStrs.append("Apple")
someStrs.append("Amazon")
someStrs.append("Runoob")
someStrs += ["Google"]

for (index, item) in someStrs.enumerated() {
    print("在 index = \(index) 位置上的值为 \(item)")
}

//合并数组:可以使用加法操作符(+)来合并两种已存在的相同类型数组
var intsA = [Int](repeating: 2, count:2)
var intsB = [Int](repeating: 1, count:3)

var intsC = intsA + intsB
for item in intsC {
    print(item)
}

//count属性
var intsA = [Int](count:2, repeatedValue: 2)
var intsB = [Int](count:3, repeatedValue: 1)

var intsC = intsA + intsB

print("intsA 元素个数为 \(intsA.count)")
print("intsB 元素个数为 \(intsB.count)")
print("intsC 元素个数为 \(intsC.count)")

//isEmpty 属性
var intsA = [Int](count:2, repeatedValue: 2)
var intsB = [Int](count:3, repeatedValue: 1)
var intsC = [Int]()

print("intsA.isEmpty = \(intsA.isEmpty)")
print("intsB.isEmpty = \(intsB.isEmpty)")
print("intsC.isEmpty = \(intsC.isEmpty)")
4.字典

Swift 字典用来存储无序的相同类型数据的集合,Swift 字典会强制检测元素的类型,如果类型不同则会报错。

//创建字典
var someDict:[Int:String] = [1:"one", 2:"two", 3:"three"]
//访问字典
var someVar = someDict[1]
print(someVar)
//修改字典
someDict[2] = "twotwo"
someDict[1] = nil //删除对应的key,value
//遍历字典
for (key, value) in someVar {
  print("key:\(key), value:\(value)")
}
//字典转数组
let dictKeys = [Int](someDict.keys)
let dictValues = [String][someDict.values]
for key in dictKeys {
  print(key)
}

//count属性
print("someDict有\(someDict.count)个键值对")

//isEmpty属性
print("someDict是否为空:\(someDict.isEmpty)")

5.函数
//带参数的函数
func runoob(name: String, site: String) -> String {
  return name + site
}

//不带参数的函数
func sitename() -> String {
  return "hello world"
}

//没有返回值的函数
func runoob(site: String) {
  print(site)
}

//局部参数名,在函数的实现内部使用
func sample(number: Int) {
  print(number)
}
//外部参数名,在函数调用时传递给函数的参数
func add(firstArg a: Int, secondArg b: Int) -> Int {
  return a + b
}
add(firstArg: 1, secondArg: 2)

//外部参数可能通过_声明成省略模式
func add2(_ a: Int, _ b: Int) -> Int {
  return a + b
}
add2(1, 2)

//元组作为返回值
func minMax(array: [Int]) -> (min: Int, max: Int) {
  var currentMin = array[0]
  var currentMax = array[0]
  for value in array {
    if value < currentMin {
      currentMin = value
    } else if value > currentMax {
      currentMax = value
    }
  }
  return (currentMin, currentMax)
}
let bounds = minMax(array: [0, -5, 10, 30, -11])
print("min:\(bounds.min) max:\(bounds.max)")

//可变参数
func sum(members: Int...) -> Int {
  var ret = 0
  for i in members {
    ret += i
  }
  return ret
}
sum(members: 1, 2, 3, 4)

//变量参数,在参数类型前面加inout
func swapInts(_ a: inout Int, _ b: inout Int) {
  let temp = a
  a = b
  b = temp
}
var x = 1
var y = 3
swapInts(&x, &y)
print("x: \(x), y: \(y)")
6.闭包

闭包(Closures)是自包含的功能代码块,可以在代码中使用或者用来作为参数传值。全局函数和嵌套函数其实就是特殊的闭包。

全局函数 嵌套函数 闭包表达式
有名字但不能捕获任何值。 有名字,也能捕获封闭函数内的值。 无名闭包,使用轻量级语法,可以根据上下文环境捕获值。
//语法
{(parameters) -> return type in
   statements
}

let divide = {(val1: Int, val2: Int) -> Int in
  return val1 / val2
}
let result = divide(200, 20)
print(result)

//闭包表达式
let names = ["AT", "AE", "D", "S", "BE"]
func backwards(s1: String, s2: String) -> Bool {
  return s1 > s2
}
var reversed = names.sorted(by: backwards)
print(reversed)

//参数名称缩写
//swift为内联函数提供了参数缩写功能,通过$0,$1来顺序调用闭包参数
var reversed = names.sorted(by: {$0 > $1})

//运算符参数
//swift的String类型定义了关于>的字符串实现,正好与sorted方法需要的参数类型相符
var reversed = names.sorted(by: >)

//尾随闭包
//尾随闭包是一个书写在函数括号之后的闭包表达式,函数支持将其作为最后一个参数调用
var reversed = names.sorted(){$0 > $1}

//捕获值
//闭包可以在其定义的上下文中捕获常量或变量。即使定义这些常量和变量的原域已经不存在,闭包仍然可以在闭包函数体内引用和修改这些值。
func makeIncrementor(forIncrement amount: Int) -> () -> Int {
  var runingTotal = 0
  func incrementor() -> Int {
    runingTotal += amount
    return runingTotal
  }
  return incrementor
}
let incrementByTen = makeIncrementor(forIncrement: 10)
print(incrementByTen())
print(incrementByTen())
print(incrementByTen())
let alsoIncrementByten = incrementByTen
print(alsoIncrementByten())
7.枚举

枚举也是一种数据类型,只包含自定义的特定数据。

//相关值,枚举中每个case是不同的数据类型,在你创建一个基于枚举成员的常量或变量时才会被设置
enum Student{
  case Name(String)
  case Mark(Int,Int,Int)
}
var stuDetails = Student.Name("Mike")
var stuMarks = Student.Mark(98,97,96)
switch stuMarks {
  case .Name(let studName):
    print("name is: \(studName)")
  case .Mark(let Mark1, let Mark2, let Mark3):
    print("student mark is : \(Mark1), \(Mark2), \(Mark3)")
}

//原始值,可以是字符串、字符、整型、浮点型,每个原始值在它的枚举声明中必须是唯一的
enum Month: Int {
  case January = 1,February, march, April, May, June, July, August, September
}
let yearMonth = Month.May.rawValue
print(yearMonth)
7.类和结构体

Swift 中类和结构体有很多共同点。共同处在于:

与结构体相比,类还有如下的附加功能:

//结构体
struct MarksStruct {
  var mark: Int
  init(mark: Int) {
    self.mark = mark
  }
}
var aStruct = MarksStruct(mark: 98)
var bStruct = aStruct
bStruct.mark = 97
print(aStruct.mark)
print(bStruct.mark)

//类
class MarksStruct {
  var mark: Int
  init(mark: Int) {
    self.mark = mark
  }
}
var aStruct = MarksStruct(mark: 98)
var bStruct = aStruct //类是引用类型
bStruct.mark = 97
print(aStruct.mark)
print(bStruct.mark)
8.swift属性

属性可分为存储属性和计算属性:

存储属性 计算属性
存储常量或变量作为实例的一部分 计算(而不是存储)一个值
用于类和结构体 用于类、结构体和枚举
//存储属性,一个存储属性就是存储在特定类或结构体的实例里的一个常量或变量。存储属性可以是变量存储属性(用关键字var定义),也可以是常量存储属性(用关键字let定义)
struct Number{
  var digits: Int
  let pi = 3.14
}
var n = Number(digits: 12345)
n.digits = 44
print(n.digits)

//延时存储属性,当第一次被调用的时候才会计算其初始值的属性。
class number {
  let name = "hello world"
}
class sample {
  lazy var no = number() //必须是var
}
var firstsample = sample()
print(firstsample.no.name)

//计算属性,计算属性不直接存储值,而是提供一个 getter 来获取值,一个可选的 setter 来间接设置其他属性或变量的值
class sample {
  var no1 = 0.0, no2 = 0.0
  var length = 300.0, breadth = 150.0
  var middle: (Double, Double) {
    get {
      return (length / 2, breadth / 2)
    }
    set(axis) {
      no1 = axis.0 - (length / 2)
      no2 = axis.1 - (breadth / 2)
    }
  }
}
var result = sample()
print(result.middle)
result.middle = (0.0, 10.0)
print(result.no1)
print(result.no2)

//属性观察器,属性观察器监控和响应属性值的变化,每次属性被设置值的时候都会调用属性观察器
class Samplepgm {
  var counter: Int = 0 {
    willSet(newValue) {
      print("计数器:\(newValue)")
    }
    didSet{
      if counter > oldValue {
        print("新增数 \(counter - oldValue)")
      }
    }
  }
}
let newcounter = Samplepgm()
newcounter.counter = 100
newcounter.counter = 800

//类型属性,使用关键字 static 来定义值类型的类型属性,关键字 class 来为类定义类型属性。
struct Structname {
  static var storedTypeProperty = ""
  static var computedTypeProperty: Int {
    return 100
  }
}

enum Enumname {
  static var storedTypeProperty = ""
  static var computedTypeProperty: Int {
    return 200
  }
}

class Classname {
  class var computedTypeProperty: Int {
    return 300
  }
}
print(Structname.computedTypeProperty)
print(Enumname.computedTypeProperty)
print(Classname.computedTypeProperty)
9.方法

实例方法:在 Swift 语言中,实例方法是属于某个特定类、结构体或者枚举类型实例的方法

类型方法:通过类型本身调用的方法叫类型方法,声明结构体和枚举的类型方法,在方法的func关键字之前加上关键字static。类可能会用关键字class来允许子类重写父类的实现方法

class Counter {
    var count = 0
    func increment() {
        count += 1
    }
    func incrementBy(amount: Int) {
        count += amount
    }
    func reset() {
        count = 0
    }
}

//在实例方法中修改值类型,在方法前增加mutating关键字
struct area {
    var length = 1
    var breadth = 1
    
    func area() -> Int {
        return length * breadth
    }
    
    mutating func scaleBy(res: Int) {
        length *= res
        breadth *= res
        
        print(length)
        print(breadth)
    }
}

//类型方法
class Math {
    class func abs(number: Int) -> Int {
        if number < 0 {
            return (-number)
        } else {
            return number
        }
    }
}

struct absno {
    static func abs(number: Int) -> Int {
        if number < 0 {
            return (-number)
        } else {
            return number
        }
    }
}

10.下标脚本

下标脚本 可以定义在类(Class)、结构体(structure)和枚举(enumeration)这些目标中,可以认为是访问对象、集合或序列的快捷方式

class daysofaweek {
  private var days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
  subscript(index: Int) -> String {
    get {
      return days[index]
    }
    set(newValue) {
      self.days[index] = newValue
    }
  }
}
var p = daysofaweek()
print(p[0])
print(p[1])
print(p[2])
print(p[3])
11.继承

继承我们可以理解为一个类获取了另外一个类的方法和属性。在 Swift 中,类可以调用和访问超类的方法,属性和下标脚本,并且可以重写它们。我们也可以为类中继承来的属性添加属性观察器。

//重写属性
class Circle {
  var radius = 12.5
  var area: String {
    return "矩形半径\(radius)"
  }
}

class Rectangle: Circle {
  var print = 7
  override var area: String {
    return super.area + ". 但现在被重写\(print)"
  }
}
let rect = Rectangle()
rect.radius = 25.0
rect.print = 3
print("Radius \(rect.area)")

//重写属性观察器
class Square: Rectangle {
  override var radius: Double {
    didSet {
        Swift.print("oldValue: \(oldValue), newValue: \(radius)")
    }
  }
}
let sq = Square()
sq.radius = 100

//防止重写,增加final关键字修饰
final class Circle {
    final var radius = 12.5
    var area: String {
        return "矩形半径为 \(radius) "
    }
}
12.构造和析构

构造过程是为了使用某个类、结构体或枚举类型的实例而进行的准备过程。这个过程包含了为实例中的每个属性设置初始值和为其执行必要的准备和初始化任务。Swift 构造函数使用 init() 方法。

//构造过程中修改常量属性,只要在构造过程结束前常量的值能确定,你可以在构造过程中的任意时间点修改常量属性的值。
struct Rectangle {
    let length: Double?
    
    init(frombreadth breadth: Double) {
        length = breadth * 10
    }
    
    init(frombre bre: Double) {
        length = bre * 30
    }
    
    init(_ area: Double) {
        length = area
    }
}

let rectarea = Rectangle(180.0)
print("面积为:\(rectarea.length)")

//默认构造器,默认构造器将简单的创建一个所有属性值都设置为默认值的实例
class ShoppingListItem {
    var name: String?
    var quantity = 1
    var purchased = false
}
var item = ShoppingListItem()
print("名字为: \(item.name)")

//结构体的逐一成员构造器,如果结构体没有提供定制的构造器,它们能自动获得一个逐一成员构造器。
struct Rectangle {
    var length = 100.0, breadth = 200.0
}
let area = Rectangle(length: 24.0, breadth: 32.0)
let area1 = Rectangle()
print("矩形的面积: \(area.length)")
print("矩形的面积: \(area.breadth)")

类的继承和构造过程

Swift 提供了两种类型的类构造器来确保所有类实例中存储型属性都能获得初始值,它们分别是指定构造器和便利构造器。

指定构造器 便利构造器
类中最主要的构造器 类中比较次要的、辅助型的构造器
初始化类中提供的所有属性,并根据父类链往上调用父类的构造器来实现父类的初始化。 可以定义便利构造器来调用同一个类中的指定构造器,并为其参数提供默认值。你也可以定义便利构造器来创建一个特殊用途或特定输入的实例。
每一个类都必须拥有至少一个指定构造器 只在必要的时候为类提供便利构造器
//指定构造器
class mainClass {
    var no1 : Int // 局部存储变量
    init(no1 : Int) {
        self.no1 = no1 // 初始化
    }
}
class subClass : mainClass {
    var no2 : Int // 新的子类存储变量
    init(no1 : Int, no2 : Int) {
        self.no2 = no2 // 初始化
        super.init(no1:no1) // 初始化超类
    }
}

let res = mainClass(no1: 10)
let res2 = subClass(no1: 10, no2: 20)

print("res 为: \(res.no1)")
print("res2 为: \(res2.no1)")
print("res2 为: \(res2.no2)")

//便利构造器
class mainClass {
    var no1 : Int // 局部存储变量
    init(no1 : Int) {
        self.no1 = no1 // 初始化
    }
}

class subClass : mainClass {
    var no2 : Int
    init(no1 : Int, no2 : Int) {
        self.no2 = no2
        super.init(no1:no1)
    }
    // 便利方法只需要一个参数
    override convenience init(no1: Int)  {
        self.init(no1:no1, no2:0)
    }
}
let res = mainClass(no1: 20)
let res2 = subClass(no1: 30, no2: 50)

print("res 为: \(res.no1)")
print("res2 为: \(res2.no1)")
print("res2 为: \(res2.no2)")

//类的可失败构造器
struct Animal {
    let species: String
    init?(species: String) {
        if species.isEmpty { return nil }
        self.species = species
    }
}

let someCreature = Animal(species: "长颈鹿")
if let giraffe = someCreature {
    print("动物初始化为\(giraffe.species)")
}

//枚举类型的可失败构造器
enum TemperatureUnit {
    case Kelvin, Celsius, Fahrenheit
    init?(symbol: Character) {
        switch symbol {
        case "K":
            self = .Kelvin
        case "C":
            self = .Celsius
        case "F":
            self = .Fahrenheit
        default:
            return nil
        }
    }
}


let fahrenheitUnit = TemperatureUnit(symbol: "F")
if fahrenheitUnit != nil {
    print("这是一个已定义的温度单位,所以初始化成功。")
}

let unknownUnit = TemperatureUnit(symbol: "X")
if unknownUnit == nil {
    print("这不是一个已定义的温度单位,所以初始化失败。")
}

析构过程原理

Swift 会自动释放不再需要的实例以释放资源。

Swift 通过自动引用计数(ARC)处理实例的内存管理。

通常当你的实例被释放时不需要手动地去清理。但是,当使用自己的资源时,你可能需要进行一些额外的清理。

    var counter = 0;  // 引用计数器
class BaseClass {
    init() {
        counter += 1;
    }
    deinit {
        counter -= 1;
    }
}

var show: BaseClass? = BaseClass()
print(counter)
show = nil
print(counter)
13.可选链

可选链(Optional Chaining)是一种可以请求和调用属性、方法和子脚本的过程,用于请求或调用的目标可能为nil。可选链返回两个值:

class Person {
    var residence: Residence?
}

class Residence {
    var numberOfRooms = 1
}

let john = Person()

// 链接可选residence?属性,如果residence存在则取回numberOfRooms的值
if let roomCount = john.residence?.numberOfRooms {
    print("John 的房间号为 \(roomCount)。")
} else {
    print("不能查看房间号")
}
14.扩展

扩展就是向一个已有的类、结构体或枚举类型添加新功能。

扩展可以对一个类型添加新的功能,但是不能重写已有的功能。

Swift 中的扩展可以:

//计算型属性
extension Int {
   var add: Int {return self + 100 }
   var sub: Int { return self - 10 }
   var mul: Int { return self * 10 }
   var div: Int { return self / 5 }
}
    
let addition = 3.add
print("加法运算后的值:\(addition)")
    
let subtraction = 120.sub
print("减法运算后的值:\(subtraction)")
    
let multiplication = 39.mul
print("乘法运算后的值:\(multiplication)")
    
let division = 55.div
print("除法运算后的值: \(division)")

let mix = 30.add + 34.sub
print("混合运算结果:\(mix)")

//方法
extension Int {
   func topics(summation: () -> ()) {
      for _ in 0..<self {
         summation() 
      }
   }
}  

4.topics({
   print("扩展模块内")       
})    
    
3.topics({
   print("内型转换模块内")       
})   
15.协议

协议规定了用来实现某一特定功能所必需的方法和属性。

任意能够满足协议要求的类型被称为遵循(conform)这个协议。

类,结构体或枚举类型都可以遵循协议,并提供具体实现来完成协议定义的方法和功能

//对属性的规定
//协议用于指定特定的实例属性或类属性,而不用指定是存储型属性或计算型属性。此外还必须指明是只读的还是可读可写的。
protocol classa {
    
    var marks: Int { get set }
    var result: Bool { get }
    
    func attendance() -> String
    func markssecured() -> String
    
}

protocol classb: classa {
    
    var present: Bool { get set }
    var subject: String { get set }
    var stname: String { get set }
    
}

class classc: classb {
    var marks = 96
    let result = true
    var present = false
    var subject = "Swift 协议"
    var stname = "Protocols"
    
    func attendance() -> String {
        return "The \(stname) has secured 99% attendance"
    }
    
    func markssecured() -> String {
        return "\(stname) has scored \(marks)"
    }
}

协议的继承

协议能够继承一个或多个其他协议,可以在继承的协议基础上增加新的内容要求。

协议的继承语法与类的继承相似,多个被继承的协议间用逗号分隔:

protocol InheritingProtocol: SomeProtocol, AnotherProtocol {
    // 协议定义
}

类专属协议

你可以在协议的继承列表中,通过添加class关键字,限制协议只能适配到类(class)类型。

该class关键字必须是第一个出现在协议的继承列表中,其后,才是其他继承协议

protocol SomeClassOnlyProtocol: class, SomeInheritedProtocol {
    // 协议定义
}

协议合成

Swift 支持合成多个协议,这在我们需要同时遵循多个协议时非常有用

protocol Stname {
    var name: String { get }
}

protocol Stage {
    var age: Int { get }
}

struct Person: Stname, Stage {
    var name: String
    var age: Int
}

func show(celebrator: Stname & Stage) {
    print("\(celebrator.name) is \(celebrator.age) years old")
}

检验协议的一致性

你可以使用is和as操作符来检查是否遵循某一协议或强制转化为某一类型。

16.泛型

Swift 提供了泛型让你写出灵活且可重用的函数和类型。

struct Stack<Element> {
    var items = [Element]()
    mutating func push(_ item: Element) {
        items.append(item)
    }
    mutating func pop() -> Element {
        return items.removeLast()
    }
}
 
extension Stack {
    var topItem: Element? {
       return items.isEmpty ? nil : items[items.count - 1]
    }
}
 
var stackOfStrings = Stack<String>()
print("字符串元素入栈: ")
stackOfStrings.push("google")
stackOfStrings.push("runoob")
 
if let topItem = stackOfStrings.topItem {
    print("栈中的顶部元素是:\(topItem).")
}
 
print(stackOfStrings.items)

类型约束

类型约束指定了一个必须继承自指定类的类型参数,或者遵循一个特定的协议或协议构成。

func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) {
    // 这里是泛型函数的函数体部分
}

关联类

Swift 中使用 associatedtype 关键字来设置关联类型实例。相当于泛型协议

// Container 协议
protocol Container {
    associatedtype ItemType
    // 添加一个新元素到容器里
    mutating func append(_ item: ItemType)
    // 获取容器中元素的数
    var count: Int { get }
    // 通过索引值类型为 Int 的下标检索到容器中的每一个元素
    subscript(i: Int) -> ItemType { get }
}

// Stack 结构体遵从 Container 协议
struct Stack<Element>: Container {
    // Stack<Element> 的原始实现部分
    var items = [Element]()
    mutating func push(_ item: Element) {
        items.append(item)
    }
    mutating func pop() -> Element {
        return items.removeLast()
    }
    // Container 协议的实现部分
    mutating func append(_ item: Element) {
        self.push(item)
    }
    var count: Int {
        return items.count
    }
    subscript(i: Int) -> Element {
        return items[i]
    }
}

var tos = Stack<String>()
tos.push("google")
tos.push("runoob")
tos.push("taobao")
// 元素列表
print(tos.items)
// 元素个数
print( tos.count)

where语句

你可以在参数列表中通过where语句定义参数的约束。你可以写一个where语句,紧跟在在类型参数列表后面,where语句后跟一个或者多个针对关联类型的约束,以及(或)一个或多个类型和关联类型间的等价(equality)关系。

// Container 协议
protocol Container {
    associatedtype ItemType
    // 添加一个新元素到容器里
    mutating func append(_ item: ItemType)
    // 获取容器中元素的数
    var count: Int { get }
    // 通过索引值类型为 Int 的下标检索到容器中的每一个元素
    subscript(i: Int) -> ItemType { get }
}
 
// // 遵循Container协议的泛型TOS类型
struct Stack<Element>: Container {
    // Stack<Element> 的原始实现部分
    var items = [Element]()
    mutating func push(_ item: Element) {
        items.append(item)
    }
    mutating func pop() -> Element {
        return items.removeLast()
    }
    // Container 协议的实现部分
    mutating func append(_ item: Element) {
        self.push(item)
    }
    var count: Int {
        return items.count
    }
    subscript(i: Int) -> Element {
        return items[i]
    }
}
// 扩展,将 Array 当作 Container 来使用
extension Array: Container {}
 
func allItemsMatch<C1: Container, C2: Container>
    (_ someContainer: C1, _ anotherContainer: C2) -> Bool
    where C1.ItemType == C2.ItemType, C1.ItemType: Equatable {
        
        // 检查两个容器含有相同数量的元素
        if someContainer.count != anotherContainer.count {
            return false
        }
        
        // 检查每一对元素是否相等
        for i in 0..<someContainer.count {
            if someContainer[i] != anotherContainer[i] {
                return false
            }
        }
        
        // 所有元素都匹配,返回 true
        return true
}
var tos = Stack<String>()
tos.push("google")
tos.push("runoob")
tos.push("taobao")
 
var aos = ["google", "runoob", "taobao"]
 
if allItemsMatch(tos, aos) {
    print("匹配所有元素")
} else {
    print("元素不匹配")
}
上一篇下一篇

猜你喜欢

热点阅读