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会报错,主要用做封装,不想外面调用者知道实际是什么对象