斯威夫特学习_扩大和商业事务,斯威夫特学习

图片 1Swift

泛型能够让开发者编写自定义需求已经任意类型的灵活可用的的函数和类型。能够让我们避免重复的代码。用一种清晰和抽象的方式来表达代码的意图。

图片 2Swift

泛型能够让开发者编写自定义需求已经任意类型的灵活可用的的函数和类型。能够让我们避免重复的代码。用一种清晰和抽象的方式来表达代码的意图。
// 定义一个Animal协议protocol Animal{ var getName:String{get}}// 定义一个Dog类,但是没有采纳Animal协议class Dog{ func shout() -> String{ return "汪汪汪" }}// 通过扩展采纳并实现Animal协议extension Dog:Animal{ var getName:String{ return "泰迪" }}let dog = Dog()print("狗的叫声(dog.shoutprint("狗的名字(dog.getName)")

1.泛型解决的问题

扩展用于为已存在的类、结构体或枚举等类型添加新的功能

1.泛型解决的问题

当一个类型已经符合了每个协议中的所有要求,却没有声明采纳该协议时,类型并不会自动采纳协议,此时,可以通过一个实现体为空的扩展来采纳该协议

下面是一个非泛型的例子
func swapTwoIntValue(a: inout Int, b: inout Int){  
    let tempValue = a  
    a = b  
    b = tempValue  
}
extension Double{ var km:Double{ return self * 1_000 } var m:Double{ return self } var cm:Double{ return self / 100.0 } var mm:Double{ return self / 1_000.0 }}let oneKilometer = 1.kmprint("一公里等于(oneKilometer)米")let tenmilimeter = 10.mmprint("10毫米等于(tenmilimeter)米")let aMarathon = 43.km   195.mprint("马拉松的长度是(aMarathon)米")
下面是一个非泛型的例子
func swapTwoIntValue(inout a:Int,inout b:Int){ //使用inout关键字可以修改传入的数值的原始值。 let tempValue = a a = b b = tempValue}
protocol Getname{ var getName:String{get}}// 定义一个Student结构体struct Student { var name:String var getName:String{ return "这个学生的名字是" }}extension Student:Getname{}let people = Student(name:"小明")print(people.getName)let student:Getname = peopleprint(student.getName)

protocol People{ func drink() -> String}// 扩展新增方法并实现,此时必须实现extension People{ func eat() -> String { return "吃骨头" } func legs() -> Int { return 2 }}class Teacher: People { func drink() -> String { return "喝水" }}let teacher = Teacher()print(teacher.drinkprint(teacher.eatprint("人类(teacher.legs
这个函数用来交换两个整形的数值
var a = 1  
var b = 2  
swapTwoIntValue(a: &a, b: &b)  
print(a, b)//2,1 

扩展构造函数是为一个类型添加新的构造函数

这个函数用来交换两个整形的数值
var oneInt = 3var twoInt = 4swapTwoIntValue(&oneInt, b: &twoInt)print(oneInt,twoInt) //oneInt = 4,twoInt = 3

图片 3协议和扩展的结合结果输出

对于这个例子,假如我们想交换两个Double类型、或者是其他类型的值,就需要针对每个类型写不同的方法,只是参数类型不同。为了解决这个问题,Swift提供了泛型,帮助我们来解决这个问题。
struct Size{ var width = 0.0, height = 0.0}struct Point { var x = 0.0, y = 0.0}struct Rect { var origin = Point() var size = Size()}let defaultRect = Rect()let memberwiseRect = Rect(origin:Point(x:2.0,y:2.0),size:Size(width:5.0,height:5.0))extension Rect{ init(center:Point,size:Size) { let originX = center.x - size.width/2 let originY = center.y - size.height/2 self.init(origin:Point(x: originX, y: originY),size:size) }}let centerRect = Rect(center: Point(x: 4.0, y: 4.0), size: Size(width: 3.0, height: 3.0))print("默认构造函数实例(defaultRect)")print("成员构造函数实例(memberwiseRect)")print("扩展构造函数实例(centerRect)")

extension Int{ static var num:Int = 4 func legInt() -> Int { return self * Int.num } // 定义一个可变方法 mutating func legInt1(){ self = self * Int.num }}let cat = 6.legInt()print("6只猫有var cat1 = 6cat1.legInt1()print("6只猫有
对于这个例子,假如我们想交换两个Double类型、或者是其他类型的值,就需要针对每个类型写不同的方法,只是参数类型不同。为了解决这个问题,Swift提供了泛型,帮助我们来解决这个问题。
代码已上传至git:
注意:Swift是安全的语言,不允许两个不同类型互换值

使用 mutating 关键字修饰方法是为了能在该方法中修改 struct 或是 enum 的变量,在设计接口的时候,也要考虑到使用者程序的扩展性。所以要多考虑使用mutating来修饰方法。

注意:Swift是安全的语言,不允许两个不同类型互换值
--> 传送门:Swift_基本语法

2.泛型函数

extension Int{ subscript -> Int{ var base = 1 for _ in 0..<i { base *= 10 } return (self / base) % 10 }}print("输出个位的值:")print("输出十位的值:")print("输出白位的值:")print("输出千位的值:")print("输出万位的值:")

2.泛型函数

下面是一个泛型的函数
func swapTwoValue<T>(a: inout T, b: inout T){  
    let tempValue = a  
    a = b  
    b = tempValue  
}  

subscript:在swift中,subscript可以帮助我们更方便的访问或者设置一个集合中的某个成员。

swift中的协议用于定义方法和属性,但协议本身并不进行实现,而是由采纳该协议的类具体实现,与Objective-C不用的是,协议还可以被结构体和枚举采纳。

下面是一个泛型的函数
func SwapTwoValues <T> (inout a: T,inout b :T){ let tempValue = a a = b b = tempValue}
这个函数主体、功能跟上面的例子类似,用来交换两个同样类型的值,但是这个函数用 T 占位符来代替实际的类型。并没有指定具体的类型,但是传入的a ,b 必须是同一类型T。在调用这个函数的时候才能指定 T 是那种具体的类型。还有函数名后跟的那个 <T> 是函数定义的一个占位类型名,并不会查找T的具体类型
swapTwoValue(&oneInt, b: &twoInt)  
print("oneInt:(oneInt),twoInt:(twoInt)") // oneInt:3,twoInt:4  

var oneStr = "hello"  
var twoStr = "world"  

swapTwoValue(&oneStr, b: &twoStr)  
print("oneStr:(oneStr),twoStr:(twoStr)")// oneStr:world,twoStr:hello  

var oneDouble = 10.01  
var twoDouble = 20.02  
swapTwoValue(&oneDouble, b: &twoDouble)  
print("oneDouble:(oneDouble),twoDouble:(twoDouble)")// oneDouble:20.02,twoDouble:10.01    
protocol 协议名称{ // 协议内容}protocol 协议名称2{}protocol 协议名称1:class { // 协议内容}

struct 结构体名称:协议名称 { // 结构体内容}

struct 结构体名称1:协议名称,协议名称2{ //结构体名称}class 子类名称: 父类名称,协议名称 { }

protocol Animal{ // 在协议中声明实例方法 func shout() // 在协议中声明类方法 static func eat()}class Dog: Animal { func shout() { print } static func eat() { print }}

protocol Button{ mutating func toggle()}enum OnOffSwitch:Button { case Off,On // 定义两个枚举值 mutating func toggle() { if self == OnOffSwitch.On{ self = .Off print }else{ self = .On print } }}var lightSwitch = OnOffSwitch.Off //关lightSwitch.toggle() //开lightSwitch.toggle() //关lightSwitch.toggle() //开

protocol MakeFood{ init()}class Personx { init(){ print }}class Cook: Personx,MakeFood { required override init() { print("厨师做的饭更好吃") }}
这个函数主体、功能跟上面的例子类似,用来交换两个同样类型的值,但是这个函数用 T 占位符来代替实际的类型。并没有指定具体的类型,但是传入的a ,b 必须是同一类型T。在调用这个函数的时候才能指定 T 是那种具体的类型。还有函数名后跟的那个 <T> 是函数定义的一个占位类型名,并不会查找T的具体类型
SwapTwoValues(&oneInt, b: &twoInt)print("oneInt:,twoInt: // oneInt:3,twoInt:4var oneStr = "hello"var twoStr = "world"SwapTwoValues(&oneStr, b: &twoStr)print("oneStr:,twoStr:// oneStr:world,twoStr:hellovar oneDouble = 10.01var twoDouble = 20.02SwapTwoValues(&oneDouble, b: &twoDouble)print("oneDouble:(oneDouble),twoDouble:(twoDouble)")// oneDouble:20.02,twoDouble:10.01
这个例子用泛型完美的解决了上述的问题,只需要定义一个泛型函数,只要保证 传入的两个参数是同一个类型,就不用根据传入参数的类型不同而写不同的方法。

可选协议表示定义协议的属性和方法可以实现也可以不实现

这个例子用泛型完美的解决了上述的问题,只需要定义一个泛型函数,只要保证 传入的两个参数是同一个类型,就不用根据传入参数的类型不同而写不同的方法。

3.类型参数

@objc protocol Animals{ @objc optional func wing()}class Bird: Animals { @objc func wing() { print }}// 这个实现方法不写也不会报错,例如下面例子class Tiger:Animals{ }let bird = Bird()bird.wing()

3.类型参数

在上面的泛型函数例子中,占位符T是类型参数的一个例子。类型参数指定并命名一个占位符类型,并用<>包裹,放在函数名后面。一旦一个参数类型确定,就可以指定参数类型,或者返回值的类型,还可以用作函数体的注释类型。在调用的时候会被实际的类型替代,如传递的是Int,就替换为Int,如果传入的是Double类型就替换为Double等等

协议作为类型使用

  1. 作为函数、方法或构造函数中的参数类型或返回值类型

  2. 作为常量、变量或属性的类型

  3. 作为数组、字典或其他容器中的元素类型

在上面的泛型函数例子中,占位符T是类型参数的一个例子。类型参数指定并命名一个占位符类型,并用<>包裹,放在函数名后面。一旦一个参数类型确定,就可以指定参数类型,或者返回值的类型,还可以用作函数体的注释类型。在调用的时候会被实际的类型替代,如传递的是Int,就替换为Int,如果传入的是Double类型就替换为Double等等

4.命名类型参数

protocol Name{ var name:String{get}}struct Student:Name { var name:String}func contact(student:Name){ print("要联系的学生的名字是(student.name)")}let student = Student(name:"小米")contact(student: student)print(student.name)

4.命名类型参数

上面的泛型例子的 T,只是一个描述性的名字,通常用单一的字母来命名,例如:T、U、V等。T代表只是一个占位符,命名规则同驼峰命名法

图片 4扩展和协议结果输出

上面的泛型例子的 T,只是一个描述性的名字,通常用单一的字母来命名,例如:T、U、V等。T代表只是一个占位符,命名规则同驼峰命名法

5.泛型类型

代码已上传至git:

5.泛型类型

除了定义泛型函数,还可以定义泛型类型。如Array,Dictionary的用法
--> 传送门:Swift_基本语法
除了定义泛型函数,还可以定义泛型类型。如Array,Dictionary的用法
下面展示一个非泛型版本栈
struct IntStack {  
    var items = [Int]()  
    mutating func push(item: Int) {  
        items.append(item)  
    }  
    mutating func pop(item: Int) -> Int {  
        return items.removeLast()  
    }  
} 
下面展示一个非泛型版本栈
struct IntStack{ var items = [Int]() //压栈 mutating func push{ items .append } //出栈 mutating func pop()->Int{ return items.removeLast() }}
这个是一个泛型版本的栈
struct Stack<T> {  
    var items = [T]()  
    mutating func push(item: T) {  
        items.append(item)  
    }  
    mutating func pop(item: T) -> T {  
        return items.removeLast()  
    }  
} 
这个是一个泛型版本的栈
struct Stack<Element>{ var items = [Element]() mutating func push(item:Element){ items.append } mutating func pop()->Element{ return items.removeLast() }}
首先在函数名后面加<泛型类型名>,<>里面表明类型参数名。然后在函数主体里面完成跟非泛型栈类似的功能。这样这个泛型结构体就不只能压栈Int类型的值,还可以是其它类型
var stack = Stack<String>() //要在类型名后面加<类型名>  
stack.push("uno")  
stack.push("dos")  
stack.push("tres")  
stack.push("cuatro")  

print(stack.pop()) // cuatro  
首先在函数名后面加<泛型类型名>,<>里面表明类型参数名。然后在函数主体里面完成跟非泛型栈类似的功能。这样这个泛型结构体就不只能压栈Int类型的值,还可以是其它类型
var stack = Stack<String>() //要在类型名后面加<类型名>stack.pushstack.pushstack.pushstack.pushprint(stack.pop // cuatro

6.扩展一个泛型类型

6.扩展一个泛型类型

可以扩展一个泛型类型,给这个泛型类型添加属性、方法、下标等。
extension Stack{  
    //给泛型Stack扩展一个计算型属性topItem,返回最上面的item  
    var topItem: T? {  
        return items.isEmpty ? nil : items[items.count-1]  
    }  
} 
可以扩展一个泛型类型,给这个泛型类型添加属性、方法、下标等。
extension Stack{ //给泛型Stack扩展一个计算型属性topItem,返回最上面的item var topItem:Element?{ return items.isEmpty ? nil : items[items.count-1] }}print("stack's top item is : (stack.topItem!)") //stack's top item is : tres

7.类型约束

7.类型约束

在上面的SwapTwoVlues 和 Stack中,可以作用任何类型。但是也可以添加一个约束,比如指定一个类型必须采纳某协议或者是指定类等。在Swift中(Bool,Int,Doube,String默认都是哈希的),Dictionary的键就需要必须是可哈希的,方便字典查找是否已包含某个键的值。
在上面的SwapTwoVlues 和 Stack中,可以作用任何类型。但是也可以添加一个约束,比如指定一个类型必须采纳某协议或者是指定类等。在Swift中(Bool,Int,Doube,String默认都是哈希的),Dictionary的键就需要必须是可哈希的,方便字典查找是否已包含某个键的值。
类型约束语法
类型约束语法
可以在类型参数名后面加一个类型或者协议名,通过冒号隔开,多个类型参数之间用逗号隔开
func somFuntion<C:NSObject, P: NSObjectProtocol>(someClass: C, someProtocol: P){  
    //这里用NSObject和NSObjectProtocol做例子  
} 
可以在类型参数名后面加一个类型或者协议名,通过冒号隔开,多个类型参数之间用逗号隔开
func somFuntion<C:SomeClass,P:SomeProtocol>(someClass:C,someProtocol:P){ }
在定义的这个函数中,有两个类型约束,第一次类型参数C代表是某个类,第二个参数P代表某个协议。
在定义的这个函数中,有两个类型约束,第一次类型参数C代表是某个类,第二个参数P代表某个协议。

类型约束实践

这个非泛型类型的方法用来查找某个字符串是否在字符数组中,存在返回index
func findStrInArray(array:[String],strToFind:String)->Int?{ for (index,value) in array.enumerate(){ if strToFind == value{ return index } } return nil}
这个非泛型类型的方法用来查找某个字符串是否在字符数组中,存在返回index
func findStrInArray(_ array: [String], strToFind: String) -> Int?{  
    for (index,value) in array.enumerated(){  
        if strToFind == value{  
            return index  
        }  
    }  
    return nil  
}

下面这是针对上面非泛型方法泛型版本的方法

func findIndex<T: Equatable> (_ array: [T], _ valueToFind: T) -> Int? {  
    for  (index,value) in array.enumerated(){  
        if value == valueToFind { //如果没指定S:Equatable 这句话会编译不通过  
            return index  
        }  
    }  
    return nil  
} 
下面这是针对上面非泛型方法泛型版本的方法
func findIndex <S:Equatable> (array:[S],_ valueToFind:S)->Int? { for (index,value) in array.enumerate(){ if value == valueToFind { //如果没指定S:Equatable 这句话会编译不通过 return index } } return nil}
在这个泛型例子中,不是所有的类型都可以 用 == 来比较的,所有必须指定泛型类型参数的约束为 Swift提供的 Equatable 协议,这表示T代表的类型必须是支持 Equatable 协议的。所有的Swift标准类型默认都是支持Equatable协议的.
let value = findIndex([3.14159, 0.1, 0.25], 9.3)  
// doubleIndex 类型为 Int?,其值为 nil,因为 9.3 不在数组中  
let stringIndex = findIndex(["Mike", "Malcolm", "Andrea"], "Andrea")  
// stringIndex 类型为 Int?,其值为 2  
在这个泛型例子中,不是所有的类型都可以 用 == 来比较的,所有必须指定泛型类型参数的约束为 Swift提供的 Equatable 协议,这表示S代表的类型必须是支持 Equatable 协议的。所有的Swift标准类型默认都是支持Equatable协议的.
let value = findIndex([3.14159, 0.1, 0.25], 9.3)// doubleIndex 类型为 Int?,其值为 nil,因为 9.3 不在数组中let stringIndex = findIndex(["Mike", "Malcolm", "Andrea"], "Andrea")// stringIndex 类型为 Int?,其值为 2

8.关联类型

8.关联类型

在定义协议的时候,有时候用一个或者多个关联类型作为定义协议的一部分,关联类型作为协议的一部分,为某个类型提供了一个占位符,其实际类型会在采纳的时候被指定。并用关键字typealias 关键字来指定关联名
在定义协议的时候,有时候用一个或者多个关联类型作为定义协议的一部分,关联类型作为协议的一部分,为某个类型提供了一个占位符,其实际类型会在采纳的时候被指定。并用关键字typealias 关键字来指定关联名

关联类型实践

下面定义一个协议,协议指定了一个关联类型
protocol Container{ typealias itemType //声明一个关联类型 mutating func append(item:itemType) var count:Int{get} subscript->itemType {get}}
下面定义一个协议,协议指定了一个关联类型
protocol Container{  
    associatedtype itemType //声明一个关联类型  
    mutating func appended(item: itemType)  
    var count: Int{ get }  
    subscript(i: Int) -> itemType { get }  
}
下面是非泛型的版本采纳 Container 协议
struct intStack: Container { // IntStack 的原始实现部分 var items = [Int]() mutating func push(item: Int) { items.append } mutating func pop() -> Int { return items.removeLast() } // Container 协议的实现部分 typealias ItemType = Int mutating func append(item: Int) { self.push } var count: Int { return items.count } subscript -> Int { return items[i] }}
下面是非泛型的版本采纳 Container 协议
struct intStack: Container {  
    // IntStack 的原始实现部分  
    var items = [Int]()  
    mutating func push(item: Int) {  
        items.append(item)  
    }  
    mutating func pop() -> Int {  
        return items.removeLast()  
    }  
    //这里没设置关联类型的原因是根本不需要设置,因为很确定只返回Int型,当然你设置了也没问题。  
    // Container 协议的实现部分  
    mutating func appended(item: Int) {  
        self.push(item: item)  
    }  
    var count: Int {  
        return items.count  
    }  
    subscript(i: Int) -> Int {  
        return items[i]  
    }  
}

下面是一个泛型版本的

struct genericStack<T>: Container{  
    // genericStack<T> 的原始实现部分  
    var items = [T]()  
    mutating func push(item: T) {  
        items.append(item)  
    }  
    mutating func pop() -> T {  
        return items.removeLast()  
    }  

    //这是设置关联类型具体是什么类型  
    typealias itemType = T  

    // Container 协议的实现部分  
    mutating func appended(item: T) {  
        self.push(item: item)  
    }  
    var count: Int {  
        return items.count  
    }  
    subscript(i: Int) -> T {  
        return items[i]  
    }  
} 
下面是一个泛型版本的
struct genericStack<Element>:Container{ // genericStack<Element> 的原始实现部分 var items = [Element]() mutating func push(item: Element) { items.append } mutating func pop() -> Element { return items.removeLast() } // Container 协议的实现部分 typealias ItemType = Element mutating func append(item: Element) { self.push } var count: Int { return items.count } subscript -> Element { return items[i] }}

通过扩展一个存在类型来指定关联类型

通过扩展添加协议的一致性描述了如何利用一个已存在类型符合一个协议,这包括了使用关联协议
通过扩展添加协议的一致性描述了如何利用一个已存在类型符合一个协议,这包括了使用关联协议
Swift中的Array都满足了Container协议的要求,意味着可以扩展Array采纳Container协议,你可以通过一个空扩展来实现这点.
extension Array :Container{}
Swift中的Array都满足了Container协议的要求,意味着可以扩展Array采纳Container协议,你可以通过一个空扩展来实现这点.
extension Array :Container{  
    mutating internal func appended(item: Element) {}  
}
定义这个扩展之后,可以用Array当做Container类型使用。
定义这个扩展之后,可以用Array当做Container类型使用。
类型约束能够让我们为泛型类型添加一些约束和条件。为关联类型添加一些约束也是很有必要的。可以在参数列表中使用where子句来为关联类型添加约束。

9.Where子句

下面的例子判断两个采纳Container协议的类型是否所有的元素顺序及值都相等。
func allItemsMatch<C1:Container,C2:Container where C1.itemType == C2.itemType,C1.itemType:Equatable>(someContainer:C1,_ anotherContainer:C2) -> Bool{ if someContainer.count != anotherContainer.count{ return false } for i in 0...someContainer.count-1{ if someContainer[i] != anotherContainer[i]{ return false } } return true}
类型约束能够让我们为泛型类型添加一些约束和条件。为关联类型添加一些约束也是很有必要的。可以在参数列表中使用where子句来为关联类型添加约束。
这个泛型函数在类型参数里面添加了where子句约束,C1,C2都必须是采纳Container协议的类型,并且C1、C2的泛型类型必须相同,而且C1的泛型类型必须是采纳Equatable的。
var stackOfStrings = genericStack<String>()stackOfStrings.appendstackOfStrings.appendstackOfStrings.appendvar arrayOfStrings = ["uno", "dos", "tres"] //array类型的满足Container类型,参考上面的extension Arrayif allItemsMatch(stackOfStrings, arrayOfStrings) { print("All items match.")} else { print("Not all items match.")}//结果是:All items match.
下面的例子判断两个采纳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-1{  
        if someContainer[i] != anotherContainer[i]{  
            return false  
        }  
    }  
    return true  
}    
这个泛型函数在类型参数里面添加了where子句约束,C1,C2都必须是采纳Container协议的类型,并且C1、C2的泛型类型必须相同,而且C1的泛型类型必须是采纳Equatable的。
var stackOfStrings = genericStack<String>()  
stackOfStrings.appended(item: "uno")  
stackOfStrings.appended(item: "dos")  
stackOfStrings.appended(item: "tres")  

var arrayOfStrings = ["uno", "dos", "tres"] //array类型的满足Container类型,参考上面的extension Array  

if allItemsMatch(stackOfStrings, arrayOfStrings) {  
    print("All items match.")  
} else {  
    print("Not all items match.")  
}  
//结果是:All items match. 

本文由星彩网app下载发布于计算机编程,转载请注明出处:斯威夫特学习_扩大和商业事务,斯威夫特学习

TAG标签: 星彩网app下载
Ctrl+D 将本页面保存为书签,全面了解最新资讯,方便快捷。