接下来我们来编写一个名为 Stack (栈)的泛型集合类型,栈只允许在集合的末端添加新的元素(称之为入栈),且也只能从末端移除元素(称之为出栈)。
struct
IntStack
{
var
items
=
[
Int
]
(
)
mutating
func
push
(
_
item
:
Int
)
{
items
.
append
(
item
)
mutating
func
pop
(
)
->
Int
{
return
items
.
removeLast
(
)
这个结构体在栈中使用一个名为 items 的 Array 属性来存储值。Stack 提供了两个方法:push(_:) 和 pop(),用来向栈中压入值以及从栈中移除值。这些方法被标记为 mutating,因为它们需要修改结构体的 items 数组。
上面的 IntStack 结构体只能用于 Int 类型。不过,可以定义一个泛型 Stack 结构体,从而能够处理任意类型的值。
下面是相同代码的泛型版本:
struct
Stack
<
Element
>
{
var
items
=
[
Element
]
(
)
mutating
func
push
(
_
item
:
Element
)
{
items
.
append
(
item
)
mutating
func
pop
(
)
->
Element
{
return
items
.
removeLast
(
)
var
stackOfStrings
=
Stack
<
String
>
(
)
print
(
"
字符串元素入栈:
"
)
stackOfStrings
.
push
(
"
google
"
)
stackOfStrings
.
push
(
"
runoob
"
)
print
(
stackOfStrings
.
items
)
;
let
deletetos
=
stackOfStrings
.
pop
(
)
print
(
"
出栈元素:
"
+
deletetos
)
var
stackOfInts
=
Stack
<
Int
>
(
)
print
(
"
整数元素入栈:
"
)
stackOfInts
.
push
(
1
)
stackOfInts
.
push
(
2
)
print
(
stackOfInts
.
items
)
;
实例执行结果为:
字符串元素入栈:
["google", "runoob"]
出栈元素: runoob
整数元素入栈:
[1, 2]
Stack 基本上和 IntStack 相同,占位类型参数 Element 代替了实际的 Int 类型。
以上实例中 Element 在如下三个地方被用作占位符:
创建
items
属性,使用
Element
类型的空数组对其进行初始化。
指定
push(_:)
方法的唯一参数
item
的类型必须是
Element
类型。
指定
pop()
方法的返回值类型必须是
Element
类型。
扩展泛型类型
当你扩展一个泛型类型的时候(使用 extension 关键字),你并不需要在扩展的定义中提供类型参数列表。更加方便的是,原始类型定义中声明的类型参数列表在扩展里是可以使用的,并且这些来自原始类型中的参数名称会被用作原始定义中类型参数的引用。
下面的例子扩展了泛型类型 Stack,为其添加了一个名为 topItem 的只读计算型属性,它将会返回当前栈顶端的元素而不会将其从栈中移除:
struct
Stack
<
Element
>
{
var
items
=
[
Element
]
(
)
mutating
func
push
(
_
item
:
Element
)
{
items
.
append
(
item
)
mutating
func
pop
(
)
->
Element
{
return
items
.
removeLast
(
)
extension
Stack
{
var
topItem
:
Element
?
{
return
items
.
isEmpty
?
nil
:
items
[
items
.
count
-
1
]
var
stackOfStrings
=
Stack
<
String
>
(
)
print
(
"
字符串元素入栈:
"
)
stackOfStrings
.
push
(
"
google
"
)
stackOfStrings
.
push
(
"
runoob
"
)
if
let
topItem
=
stackOfStrings
.
topItem
{
print
(
"
栈中的顶部元素是:
\
(topItem).
"
)
print
(
stackOfStrings
.
items
)
实例中 topItem 属性会返回一个 Element 类型的可选值。当栈为空的时候,topItem 会返回 nil;当栈不为空的时候,topItem 会返回 items 数组中的最后一个元素。
以上程序执行输出结果为:
字符串元素入栈:
栈中的顶部元素是:runoob.
["google", "runoob"]
我们也可以通过扩展一个存在的类型来指定关联类型。
例如 Swift 的 Array 类型已经提供 append(_:) 方法,一个 count 属性,以及一个接受 Int 类型索引值的下标用以检索其元素。这三个功能都符合 Container 协议的要求,所以你只需简单地声明 Array 采纳该协议就可以扩展 Array。
以下实例创建一个空扩展即可:
extension Array: Container {}
类型约束指定了一个必须继承自指定类的类型参数,或者遵循一个特定的协议或协议构成。
类型约束语法
你可以写一个在一个类型参数名后面的类型约束,通过冒号分割,来作为类型参数链的一部分。这种作用于泛型函数的类型约束的基础语法如下所示(和泛型类型的语法相同):
func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) {
// 这里是泛型函数的函数体部分
上面这个函数有两个类型参数。第一个类型参数 T,有一个要求 T 必须是 SomeClass 子类的类型约束;第二个类型参数 U,有一个要求 U 必须符合 SomeProtocol 协议的类型约束。