Swift22-泛型

泛型所解决的问题、泛型函数、类型参数、命名类型参数、泛型类型、扩展一个泛型类型、类型约束、关联类型、泛型where语句。

泛型代码让你能够根据自定义的需求,编写出适用于任意类型、灵活可重用的函数及类型。它能让你避免代码的重复,用一种清晰和抽象的方式来表达代码的意图。

泛型是Swift最强大的特性之一,许多Swift标准库是通过泛型代码构建的。事实上,泛型的使用贯穿了整本语言手册。例如,Swift的Array和Dictionary都是泛型集合。可以构建一个Int数组,也可以创建一个String数组,甚至可以是任意其它Swift类型的数组。同样的,也可以创建存储任意指定类型的字典。

泛型所解决的问题:

func swapTwoInts(_ a:inout Int, _ b: inout Int){

  let temporaryA = a

  a = b

  b = temporaryA

}

这个函数使用输入输出参数(inout)来交换a和b的值。

var a=10

var b=90

swapTwoInts(&a,&b)

泛型函数:

泛型函数可以适用于任何类型。

func swapTwoValue<T>(_ a:inout T, _ b:inout T){

  let temp=a

  a=b

  b=temp

}

//这个函数可以交换任意类型的两个同类型变量值

类型参数:

在上面的swapTwoValues(_: _:)例子中,占位类型T是类型参数的一个例子。类型参数指定并命名一个占位类型,并且紧随在函数名后面,使用一对尖括号括起来(例如<T>)

一旦一个类型参数被指定,可以用它来定义一个函数的参数类型,或者作为函数的返回类型,还可以用作函数主体中的注释类型。在这些情况下,类型参数会在函数调用时被实际类型所替换

可以提供多个类型参数,将它们都写在尖括号中,用逗号分开。

命名类型参数:

在大多数情况下,类型参数具有一个描述性名字,例如Dictionary<Key,Value>中的Key和Value。它们告诉阅读代码的人这些类型参数和泛型函数之间的关系。然而,当它们之间没有意义的关系时,通常使用单个字母来命名。

泛型类型:

除了泛型函数,Swift还允许定义泛型函数。这些自定义类、结构体和枚举可以适用于任何类型,类似于数组和字典。

struct Stack<Element>{

  var items=[Element]()

  mutating func push(item:Element){

    items.append(item)

  }

  mutating func pop()->Element{

    return items.removeLast()

  }

}

var a=Stack<String>()

扩展一个泛型类型:

当你扩展一个泛型类型时,并不需要在扩展的定义中提供类型参数列表。原始类型定义中声明的类型参数列表在扩展中可以直接使用,并且这些来自原始类型中的参数名称会被用作原始定义中类型参数的引用。

extension Stack{

  var topItem:Element?{

    return items.isEmpty ? nil : items[items.count-1]

  }

}

类型约束:

有时候如果能将使用在泛型函数和泛型类型中的类型添加一个特定的类型约束,将会是非常有用的。类型约束可以指定一个类型参数必须继承自指定类,或者符合一个特定的协议或协议组合

例如,Swift的字典类型对字典的键的类型做了一些限制。字典的键的类型必须是可哈希的(hashable)。也就是说,必须有一种方法能够唯一地表示它。字典的键之所以要是可哈希的,是为了便于检查字典是否已经包含某个特定键的值。若没有这个要求,字典将无法判断是否可以插入或者替换某个指定键的值,也不能查找到已经存储在字典中的指定键的值。

为了实现这个要求,一个类型约束被强制加到字典的键类型上,要求其键类型必须符合Hashable协议,这时Swift标准库中定义的一个特定协议。所有的Swift基本类型都默认是可哈希的。

当创建自定义泛型类型时,可以定义自己的类型约束,这些约束将提供更为强大的泛型编程能力。抽象概念,例如可哈希的,描述的是类型在概念上的特征,而不是它们的显式类型。

类型约束语法:

可以在一个类型参数名后面放置一个类名或者协议名,并用冒号进行分隔,来定义类型约束,它们将成为类型参数列表的一部分

func someFunc<T:SomeClass, U:SomeProtocol>(someT:T, someU:U){

  //

}

上面这个函数有两个类型参数。第一个类型参数T,有一个要求是必须是SomeClass子类的类型约束;第二个类型参数U,有一个要求U必须符合SomeProtocol协议的类型约束。

类型约束实践:

。。。

Swift标准库中定义了一个Equatable协议,该协议要求任何遵循该协议的类型必须实现等式符(==)及不等符(!=),从而能对该类型的任意两个值进行比较。所有的Swift标准类型自动支持Equatable协议。

关联类型

定义一个协议时,有的时候声明一个或多个关联类型作为协议定义的一部分将会非常有用。关联类型为协议中的某个类型提供了一个占位名(或者说别名),其代表的实际类型在协议被采纳时才会被指定。可以通过associatedtype关键字来指定关联类型。

关联类型实践:

下面例子定义了一个Container协议,该协议定义了一个关联类型ItemType:

protocol Container{

  associatedtype ItemType

  mutating func append(item: ItemType)

  var count:Int { get }

  subscript(i:Int) -> ItemType { get }

}

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

Swift的Array类型已经提供append(_:)方法,一个count属性,以及一个接受Int类型索引值的下标用以检索其元素。这三个功能都符合Container协议的要求,也就意味着只需简单地声明Array采纳该协议就可以扩展Array,使其遵从Container协议。可以通过一个空扩展来实现这点

extension Array:Conainer{}

泛型where语句:

为关联类型定义约束也是非常有用的。可以在参数列表中通过where子句为关联类型定义约束通过where子句要求一个关联类型遵从某个特定的协议,以及某个特定的类型参数和关联类型必须类型相同。可以通过将where关键字紧跟在类型参数列表后面来定义where子句,where子句后跟一个或者多个针对关联类型的约束,以及一个或多个类型参数和关联类型间的相等关系。可以在函数体或者类型的大括号之前添加where子句。

func allItemsMatch<C1:Container, C2:Container>(_ someContainer:C1, _ anotherContainer:C2)->Bool where C1.ItemType == C2.ItemType, C1.ItemType:Equatable{

  //

}

被检查的两个Container可以不是相同类型的容器(也可以相同),但是它们必须拥有相同类型的元素。

原文地址:https://www.cnblogs.com/cjj-ggboy/p/12871084.html