关联类型

protocol Stackable {
    associatedtype Element
    func push(element:Element)
    func pop() -> Element
    func top() -> Element
    func count() -> Int
}

class Stack  : Stackable {
    var stacks = [String]()
    func push(element:String) {
        stacks.append(element)
    }
    func pop() -> String
    {
        stacks.removeLast()
    }
    func top() -> String
    {
        stacks.last!
    }
    func count() -> Int
    {
        stacks.count
    }
}

关联类型,一般在协议里面使用,给类型之内的类型定义提供一个占位符,比如上述代码,其中String就是实际的值而Element是占位符,类似于

typealias Elenment = String

这样一句代码,这样一个协议才能给所有栈使用,比如字符串的栈结构,Double类型的栈机构等等,甚至也可以用泛型E来替代String不过,用E代替使用的时候仍然要指定具体的数据类型

类型约束

func exchange<T: Stackable>(_ a:inout T,_ b :inout T) {
    ( a , b ) = ( b , a )
}

这是函数的约束,约束的目的就是传入的参数必须遵守Stackable这个协议,其实关联属性也可以加约束

associatedtype Elenment:Equatable

后面实现的这个类型就必须遵守Equatable

比如E就不遵守Equatable协议,所以报错

解决方式也简单,让E遵守就完事了

class Stack <E:Equatable> : Stackable {
    typealias Elenment = E    
    var stacks = [E]()
}

再复杂一点的约束条件

protocol Stackable {
    associatedtype Elenment:Equatable
}

class Stack <E:Equatable> : Stackable {
    typealias Elenment = E
    var stacks = [E]()
}

func equal<T: Stackable,T1:Stackable>(_ a:T,_ b :T1)
    where T1.Elenment == T.Elenment , T1.Elenment : Hashable
{
    print("执行了")
}
var t  = Stack<Int>()
var t1 = Stack<Int>()
var t2 = Stack<String>()
equal(t, t1)
equal(t1, t2)

t1和t2传入肯定会报错,因为Elenment是无法对应上的,一个Int一个是String,而Int本身是个结构体,所以是支持Hashable协议的所以第一句能执行

注意点(关联属性)

protocol Runable { }
class Person: Runable { var speed = { 1 } }
class Animal: Runable { var speed = { 2.0 } }
func getCls(_ type:Int) -> Runable
{
    if type == 0
    {
        return Person()
    }
    return Animal()
}

这个代码来说是没有什么问题的

protocol Runable {
    associatedtype Speed
    var speed: Speed { get }
}

但如果有关联属性就会报错了,原因是关联属性也是不确定的,里面如果这么初始化,直接返回了

****李明杰的解释是不知道Speed的具体类型,我看了下,这类型在初始化的时候不是可以确定是Int和Double了么

解决方法1:

protocol Runable {
    associatedtype Speed
    var speed: Speed { get }
}
class Person: Runable { var speed = { 1 } }
class Animal: Runable { var speed = { 2.0 } }
func getCls<T:Runable>(_ type:Int) -> T
{
    if type == 0
    {
        return Person() as! T
    }
    return Animal() as! T
}

返回一个泛型,让泛型遵守Runable协议

解决办法2:

不透明类型 some

protocol Runable {
    associatedtype Speed
    var speed: Speed { get }
}
class Person: Runable { var speed = { 1 } }
class Animal: Runable { var speed = { 2.0 } }
func getCls(_ type:Int) -> some Runable
{
    return Person()
}

但缺点也很明显,不能返回多个类型,只能返回一个类型所以用if会报错,主要用做封装,不想外面调用者知道实际是什么对象

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值