Swift-泛型(Generics)

109 阅读3分钟
  • 泛型可以将类型参数化,提高代码复用率,减少代码量
var n1 = 10
var n2 = 20
func swapValues<T>(_ a:inout T,_ b:inout T){
    (a,b) = (b,a)
}
swapValues(&n1,&n2)
print(n1,n2)
  • 泛型函数赋值给变量
func test<T1,T2>(_ t1:T1,_ t2:T2){}
var fn:(Int,Int) ->() = test

泛型类型

class Stack<E> {
    var elements = [E]()
    init(firstElement:E){
        elements.append(firstElement)
    }
    func push(_ element:E){elements.append(element)}
    func pop() ->E {elements.removeLast()}
    func top() ->E {elements.last!}
    func size() ->Int {elements.count}
}
var instack = Stack<Int>()
var stringStack = Stack<String>()
var anyStack = Stack<Any>()
//var stack = Stack<Double>(firstElement:10) 
class SubStack<E>:Stack<E> {}
struct Stack<E> {
    var elements = [E]()
    init(firstElement:E){
        elements.append(firstElement)
    }
    mutating func push(_ element:E){elements.append(element)}
    mutating func pop() ->E {elements.removeLast()}
    func top() ->E {elements.last!}
    func size() ->Int {elements.count}
}
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 // 关联类型
    mutating func push(_ element:Element)
    mutating func pop() -> Element
    func top() ->Element
    func size() ->Int
} 
class StringStack : Stackable {
    // 给关联类型设定真实类型
    // typealias Element = String
    var elements = [String]()
    func push(_ element:String){elements.append(element)}
    func pop() ->String {elements.removeLast()}
    func top() ->String {elements.last!}
    func size() -> Int {elements.count}
}
var ss = StringStack()
ss.push("Jack")
ss.push("Rose")

class Stack<E>:Stackable {
    var elements = [E]()
    func push(_ element:E){
        elements.append(element)
    }
    func pop ->E {elements.removeLase()}
    func top -> E {elements.last!}
    func size() -> Int{elements.count}
}

类型约束

protocol Runnable {}
class Person {}
func swapValues<T:Person & Runnable>(_ a:inout T,_ b:inout T){
    (a,b) = (b,a)
}
protocol Stackable {
    associatedtype Element:Equatable
}
class Stack<E:Equatable>:Stackable{
   typealias Element = E
}
func equal<S1:Stackable,S2:Stackable>(_ s1:S1,_ s2:S2) -> Bool 
   where S1.Element == S2.Element,S1.Element:Hashable
{
    return false
}

var s1 = Stack<Int>()
var s2 = Stack<Int>()
var s3 = Stack<String>()
equal(s1,s2)

协议类型的注意点

protocol Runnable {}
class Person:Runnable{}
class Car:Runnable{}
func get(_ type:Int) -> Runnable {
    if type == 0 {
        return Person()
    }
    return Car()
}
var r1 = get0) // person
var r2 = get(1) // car

如果协议中有associatedtype,

protocol Runnable{
    associatedtype Speed // 关联类型
    var speed:Speed{get}
}
class Person : Runnable {
    var speed : Double{0.0}
}
class Car : Runnable {
    var speed :Int {0}
}

func get(_ type: Int) - >Runnable {
    if type == 0 {
        return Person()
    }
    return Car()
}

var r1 = get(0)
var r2 = get(1)

image.png

解决办法
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)

不透明类型(Opaque Type)

  • 解决方案2:使用some关键字声明一个不透明类型,不想外界知道真实类型
  • some只能返回一种类型
func get(_ type: Int) -> some Runnable {
    return Car()
}

some

  • some除了用在返回值类型上,一般还可以用在属性类型上
protocol Runnable{
    associatedtype Speed // 关联类型
}
class Dog : Runnable {
    typealias Speed = Double
}
class Person {
    var pet : some Runnable {
        return Dog()
    }
}

可选项的本质

  • 可选项的本质是enum类型
public enum Optional<Wrapped> : ExpressibleByNilLiteral {
    case none
    case some(Wrapped)
    public init(_ some: Wrapped)
}


var age:Int? = 10
var age0:Optional<Int> = Optional<Int>.some(10)
var age1:Optional = .some(10)
var age2 = Optional.some(10)
var age3 = Optional(10)
age = nil
age = .none
var age:Int? = nil
var age0 = Optional<Int>.none
var age1:Optional<Int> = .none
var age:Int? = .none
age = 10
age = .some(20)
age = nil
swtich age {
    case let v?:print("some",v)
    case nil:print("none")
}
swtich age {
    case let .some(v):print("some",v)
    case .none:print("none")
}
var age = 10
switch age {
    case let a where a > 20 
        print(a)
    case 20:print(1)
    default:break
}

case let a // 如果写成这样是可选项绑定,是不会走到下面去判断,在swtich里面是不会解包