泛型参数化
- 泛型可以将类型参数化,提高代码复用率,减少代码量
func swapValues<T> (_ a: inout T,_ b:inout T) {
(a,b) = (b,a)
}
var num1:Int = 10
var num2:Int = 20
swapValues(&num1,&num2)
print(num1,num2)
struct Date {
var year = 0,month = 0,day = 0
}
var date1 = Date(year:2019,month:9,day:19)
var date2 = Date(year:2020,month:10,day:20)
swapValues(&date1,&date2)
print(date1,date2)
- 泛型函数赋值给变量
func test<T1,T2> (_ v1:T1,_ v2:T2){}
var fn :(Int,Double) -> () = test //注意点 函数类型
//类泛型
class Stack<E> {
var array = [E]()
func push(_ element:E) { array.append(element) }
func pop() -> E { array.removeLast() }
func top() -> E { array.last!}
func size() -> Int { array.count }
}
//结构体泛型
struct Stack<E> {
var elements = [E]()
mutating func push(_ element: E) { elements.append(element) }
mutating func pop() -> E { elements.removeLast() } }
func top() -> E { elements.last! }
func size() -> Int { elements.count }
}
var statck = Stack<Int>()
statck.push(12)
statck.push(13)
statck.push(14)
print(statck.top())
print(statck.size())
print(statck.pop())
print(statck.array)
//枚举泛型
enum Score<T> {
case point(T)
case grade(String)
}
let score0 = Score<Int>.point( 100)
let score1 = Score.point(99)
let score2 = Score.point(99.5)
let score3 = Score<Int>.grade("A")
关联类型(Associated Type)
- 关联类型的作用:给协议中用到的类型定义一个占位名称,协议不能用泛型
- 协议中可以拥有多个关联类型
protocol Stackable {
associatedtype Element
func push(_ element:Element)
func pop() -> Element
func top() -> Element
func size() -> Int
}
class Stack: Stackable {
// 给关联类型设定真实类型,也可以省略不写,编译器会推导出类型
typealias Element = String
var array = [String]()
func push(_ element:String) { array.append(element) }
func pop() -> String { array.removeLast() }
func top() -> String { array.last!}
func size() -> Int { array.count }
}
var ss = Stack()
class Stack<E>: Stackable {
// typealias Element = String
var array = [E]()
func push(_ element:E) { array.append(element) }
func pop() -> E { array.removeLast() }
func top() -> E { array.last!}
func size() -> Int { array.count }
}
var s = Stack<String>()
s.push("Jack")
s.push("Por")
print(s.array)
类型约束
protocol Runnable { }
class Person:Runnable { }
//泛型约束
func swapValues<T: Person & Runnable > (_ a :inout T,_ b :inout T) {
(a,b) = (b,a)
}
var p = Person()
var p1 = Person()
swapValues(&p,&p1)
//约束2
protocol Stackable {
associatedtype element:Equatable
}
class Stack<E:Equatable>:Stackable {
typealias element = E
}
//S1.element 表达的是关联类型
func equal<S1:Stackable,S2:Stackable>(_ s1:S1, _ s2:S2) -> Bool where
S1.element == S2.element,S2.element : Hashable
{//关联类型必须相同
return false
}
var stack1 = Stack<Int>()//Int 默认遵守Equatable,Hashable协议
var stack2 = Stack<String>()
// error: requires the types 'Int' and 'String' be equivalent
print(equal(stack1, stack2))
协议类型的注意点
protocol Runnable { }
class Person: Runnable { }
class Car: Runnable { }
func get(_ type: Int) -> Runnable {
if type == 0 {
return Person()
}
return Car()
}
//这个不会报错
var r1:Person = get(0)
var r2:Car = get(1)
===========如果协议中有associatedtype===============
protocol Runnable {
associatedtype Speed
var speed:Speed { get }
}
class Person: Runnable {
var speed: Double { 0.0 }
}
class Car: Runnable {
var speed: Int { 0 }
}
//Protocol 'Runnable' can only be used as a generic constraint because it has Self or associated type requirements
//报错的原因是 ,函数返回两个值 无法确定关联值的类型 处理方式 使用泛型
func get(_ type: Int) -> Runnable {
if type == 0 {
return Person()
}
return Car()
}
//处理方式一 存在一点风险性
func get<T: Runnable>(_ type: Int) -> T {
if type == 0 {
return Person() as! T
}
return Car() as! T
}
//这个不会报错
var r1:Person = get(0)
var r2:Car = get(1)
//处理方式2 使用some关键字声明一个不透明类型
//some关键字 不透明处理类型,缺点:只能返回一种类型 优点:屏蔽类 内部实现,只让外部知道实现了协议里的内容
func get(_ type: Int) -> some Runnable{
return Car()
}
var r1 = get(0)
var r2 = get(1) //这个不会报错
some
- some除了用在返回值类型上,一般还可以用在属性类型上
- some 就是用来解决协议里使用大写的Self 和关联类型
使用场景: 返回遵守某个协议的类型,不想暴露协议的类型
//some 就是用来解决大写的Self 和关联类型
protocol Runnable {
associatedtype Speed
}
class Dog: Runnable {
typealias Speed = Double
}
class Person {
var pet: some Runnable {
Dog()
}
}