-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path22_Generics.html
982 lines (686 loc) · 54.4 KB
/
22_Generics.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
<!DOCTYPE HTML>
<html lang="en-US" manifest="../manifest.appcache">
<head prefix="og: http://ogp.me/ns# book: http://ogp.me/ns/book#">
<meta charset="UTF-8">
<title>《The Swift Programming Language》中文版</title>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
<meta name="robots" content="index, follow">
<meta name="author" content="">
<meta name="description" content="Swift 中文翻译组:364279588(要求对翻译感兴趣)">
<meta name="keywords" content="gitbook,github" >
<meta name="generator" content="www.gitbook.io">
<link rel="next" href="../chapter2/23_Advanced_Operators.html" />
<link rel="prev" href="../chapter2/21_Protocols.html" />
<meta property="og:title" content="泛型 | The Swift Programming Language 中文版">
<meta property="og:site_name" content="The Swift Programming Language 中文版">
<meta property="og:type" content="book">
<meta property="og:locale" content="en_US">
<meta property="book:author" content="https://github.com/">
<meta property="book:tag" content="GitBook">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<link rel="shortcut icon" href="../gitbook/images/favicon.ico" type="image/x-icon">
</head>
<body>
<link rel="stylesheet" href="../gitbook/style.css">
<div class="book" data-level="2.22" data-basepath=".." data-revision="1402551179317">
<div class="book-header">
<!-- Actions Left -->
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
<a href="https://github.com/null" target="_blank" class="btn pull-left home-bookmark" aria-label="GitHub home"><i class="fa fa-bookmark-o"></i></a>
<a href="#" class="btn pull-left toggle-search" aria-label="Toggle search"><i class="fa fa-search"></i></a>
<span id="font-settings-wrapper">
<a href="#" class="btn pull-left toggle-font-settings" aria-label="Toggle font settings"><i class="fa fa-font"></i>
</a>
<div class="dropdown-menu font-settings">
<div class="dropdown-caret">
<span class="caret-outer"></span>
<span class="caret-inner"></span>
</div>
<div class="btn-group btn-block">
<button id="reduce-font-size" class="btn btn-default">A</button>
<button id="enlarge-font-size" class="btn btn-default">A</button>
</div>
<ul class="list-group font-family-list">
<li class="list-group-item" data-font="0">Serif</li>
<li class="list-group-item" data-font="1">Sans</li>
</ul>
<div class="btn-group btn-group-xs btn-block color-theme-list">
<button type="button" class="btn btn-default" id="color-theme-preview-0" data-theme="0">White</button>
<button type="button" class="btn btn-default" id="color-theme-preview-1" data-theme="1">Sepia</button>
<button type="button" class="btn btn-default" id="color-theme-preview-2" data-theme="2">Night</button>
</div>
</div>
</span>
<!-- Actions Right -->
<a href="#" target="_blank" class="btn pull-right google-plus-sharing-link sharing-link" data-sharing="google-plus" aria-label="Share on Google Plus"><i class="fa fa-google-plus"></i></a>
<a href="#" target="_blank" class="btn pull-right facebook-sharing-link sharing-link" data-sharing="facebook" aria-label="Share on Facebook"><i class="fa fa-facebook"></i></a>
<a href="#" target="_blank" class="btn pull-right twitter-sharing-link sharing-link" data-sharing="twitter" aria-label="Share on Twitter"><i class="fa fa-twitter"></i></a>
<!-- Title -->
<h1>
<i class="fa fa-spinner fa-spin"></i>
<a href="../" >The Swift Programming Language 中文版</a>
</h1>
</div>
<div class="book-summary">
<div class="book-search">
<input type="text" placeholder="Search" class="form-control" />
</div>
<ul class="summary">
<li data-level="0" data-path="index.html">
<a href="../"><i class="fa fa-check"></i> 序</a>
</li>
<li class="chapter " data-level="1" data-path="chapter1/chapter1.html">
<a href="../chapter1/chapter1.html">
<i class="fa fa-check"></i> <b>1.</b> 欢迎使用 Swift
</a>
<ul class="articles">
<li class="chapter " data-level="1.1" data-path="chapter1/01_swift.html">
<a href="../chapter1/01_swift.html">
<i class="fa fa-check"></i> <b>1.1.</b> 关于 Swift
</a>
</li>
<li class="chapter " data-level="1.2" data-path="chapter1/02_a_swift_tour.html">
<a href="../chapter1/02_a_swift_tour.html">
<i class="fa fa-check"></i> <b>1.2.</b> Swift 初见
</a>
</li>
</ul>
</li>
<li class="chapter " data-level="2" data-path="chapter2/chapter2.html">
<a href="../chapter2/chapter2.html">
<i class="fa fa-check"></i> <b>2.</b> Swift 教程
</a>
<ul class="articles">
<li class="chapter " data-level="2.1" data-path="chapter2/01_The_Basics.html">
<a href="../chapter2/01_The_Basics.html">
<i class="fa fa-check"></i> <b>2.1.</b> 基础部分
</a>
</li>
<li class="chapter " data-level="2.2" data-path="chapter2/02_Basic_Operators.html">
<a href="../chapter2/02_Basic_Operators.html">
<i class="fa fa-check"></i> <b>2.2.</b> 基本运算符
</a>
</li>
<li class="chapter " data-level="2.3" data-path="chapter2/03_Strings_and_Characters.html">
<a href="../chapter2/03_Strings_and_Characters.html">
<i class="fa fa-check"></i> <b>2.3.</b> 字符串和字符
</a>
</li>
<li class="chapter " data-level="2.4" data-path="chapter2/04_Collection_Types.html">
<a href="../chapter2/04_Collection_Types.html">
<i class="fa fa-check"></i> <b>2.4.</b> 集合类型
</a>
</li>
<li class="chapter " data-level="2.5" data-path="chapter2/05_Control_Flow.html">
<a href="../chapter2/05_Control_Flow.html">
<i class="fa fa-check"></i> <b>2.5.</b> 控制流
</a>
</li>
<li class="chapter " data-level="2.6" data-path="chapter2/06_Functions.html">
<a href="../chapter2/06_Functions.html">
<i class="fa fa-check"></i> <b>2.6.</b> 函数
</a>
</li>
<li class="chapter " data-level="2.7" data-path="chapter2/07_Closures.html">
<a href="../chapter2/07_Closures.html">
<i class="fa fa-check"></i> <b>2.7.</b> 闭包
</a>
</li>
<li class="chapter " data-level="2.8" data-path="chapter2/08_Enumerations.html">
<a href="../chapter2/08_Enumerations.html">
<i class="fa fa-check"></i> <b>2.8.</b> 枚举
</a>
</li>
<li class="chapter " data-level="2.9" data-path="chapter2/09_Classes_and_Structures.html">
<a href="../chapter2/09_Classes_and_Structures.html">
<i class="fa fa-check"></i> <b>2.9.</b> 类和结构体
</a>
</li>
<li class="chapter " data-level="2.10" data-path="chapter2/10_Properties.html">
<a href="../chapter2/10_Properties.html">
<i class="fa fa-check"></i> <b>2.10.</b> 属性
</a>
</li>
<li class="chapter " data-level="2.11" data-path="chapter2/11_Methods.html">
<a href="../chapter2/11_Methods.html">
<i class="fa fa-check"></i> <b>2.11.</b> 方法
</a>
</li>
<li class="chapter " data-level="2.12" data-path="chapter2/12_Subscripts.html">
<a href="../chapter2/12_Subscripts.html">
<i class="fa fa-check"></i> <b>2.12.</b> 附属脚本
</a>
</li>
<li class="chapter " data-level="2.13" data-path="chapter2/13_Inheritance.html">
<a href="../chapter2/13_Inheritance.html">
<i class="fa fa-check"></i> <b>2.13.</b> 继承
</a>
</li>
<li class="chapter " data-level="2.14" data-path="chapter2/14_Initialization.html">
<a href="../chapter2/14_Initialization.html">
<i class="fa fa-check"></i> <b>2.14.</b> 构造过程
</a>
</li>
<li class="chapter " data-level="2.15" data-path="chapter2/15_Deinitialization.html">
<a href="../chapter2/15_Deinitialization.html">
<i class="fa fa-check"></i> <b>2.15.</b> 析构过程
</a>
</li>
<li class="chapter " data-level="2.16" data-path="chapter2/16_Automatic_Reference_Counting.html">
<a href="../chapter2/16_Automatic_Reference_Counting.html">
<i class="fa fa-check"></i> <b>2.16.</b> 自动引用计数
</a>
</li>
<li class="chapter " data-level="2.17" data-path="chapter2/17_Optional_Chaining.html">
<a href="../chapter2/17_Optional_Chaining.html">
<i class="fa fa-check"></i> <b>2.17.</b> 可选链
</a>
</li>
<li class="chapter " data-level="2.18" data-path="chapter2/18_Type_Casting.html">
<a href="../chapter2/18_Type_Casting.html">
<i class="fa fa-check"></i> <b>2.18.</b> 类型检查
</a>
</li>
<li class="chapter " data-level="2.19" data-path="chapter2/19_Nested_Types.html">
<a href="../chapter2/19_Nested_Types.html">
<i class="fa fa-check"></i> <b>2.19.</b> 类型嵌套
</a>
</li>
<li class="chapter " data-level="2.20" data-path="chapter2/20_Extensions.html">
<a href="../chapter2/20_Extensions.html">
<i class="fa fa-check"></i> <b>2.20.</b> 扩展
</a>
</li>
<li class="chapter " data-level="2.21" data-path="chapter2/21_Protocols.html">
<a href="../chapter2/21_Protocols.html">
<i class="fa fa-check"></i> <b>2.21.</b> 协议
</a>
</li>
<li class="chapter " data-level="2.22" data-path="chapter2/22_Generics.html">
<a href="../chapter2/22_Generics.html">
<i class="fa fa-check"></i> <b>2.22.</b> 泛型
</a>
</li>
<li class="chapter " data-level="2.23" data-path="chapter2/23_Advanced_Operators.html">
<a href="../chapter2/23_Advanced_Operators.html">
<i class="fa fa-check"></i> <b>2.23.</b> 高级操作符
</a>
</li>
</ul>
</li>
<li class="chapter " data-level="3" data-path="chapter3/chapter3.html">
<a href="../chapter3/chapter3.html">
<i class="fa fa-check"></i> <b>3.</b> 语言参考
</a>
<ul class="articles">
<li class="chapter " data-level="3.1" data-path="chapter3/01_About_the_Language_Reference.html">
<a href="../chapter3/01_About_the_Language_Reference.html">
<i class="fa fa-check"></i> <b>3.1.</b> 关于语言参考
</a>
</li>
<li class="chapter " data-level="3.2" data-path="chapter3/02_Lexical_Structure.html">
<a href="../chapter3/02_Lexical_Structure.html">
<i class="fa fa-check"></i> <b>3.2.</b> 词法结构
</a>
</li>
<li class="chapter " data-level="3.3" data-path="chapter3/03_Types.html">
<a href="../chapter3/03_Types.html">
<i class="fa fa-check"></i> <b>3.3.</b> 类型
</a>
</li>
<li class="chapter " data-level="3.4" data-path="chapter3/04_Expressions.html">
<a href="../chapter3/04_Expressions.html">
<i class="fa fa-check"></i> <b>3.4.</b> 表达式
</a>
</li>
<li class="chapter " data-level="3.5" data-path="chapter3/10_Statements.html">
<a href="../chapter3/10_Statements.html">
<i class="fa fa-check"></i> <b>3.5.</b> 语句
</a>
</li>
<li class="chapter " data-level="3.6" data-path="chapter3/05_Declarations.html">
<a href="../chapter3/05_Declarations.html">
<i class="fa fa-check"></i> <b>3.6.</b> 声明
</a>
</li>
<li class="chapter " data-level="3.7" data-path="chapter3/06_Attributes.html">
<a href="../chapter3/06_Attributes.html">
<i class="fa fa-check"></i> <b>3.7.</b> 特性
</a>
</li>
<li class="chapter " data-level="3.8" data-path="chapter3/07_Patterns.html">
<a href="../chapter3/07_Patterns.html">
<i class="fa fa-check"></i> <b>3.8.</b> 模式
</a>
</li>
<li class="chapter " data-level="3.9" data-path="chapter3/08_Generic_Parameters_and_Arguments.html">
<a href="../chapter3/08_Generic_Parameters_and_Arguments.html">
<i class="fa fa-check"></i> <b>3.9.</b> 泛型参数
</a>
</li>
<li class="chapter " data-level="3.10" data-path="chapter3/09_Summary_of_the_Grammar.html">
<a href="../chapter3/09_Summary_of_the_Grammar.html">
<i class="fa fa-check"></i> <b>3.10.</b> 语法总结
</a>
</li>
</ul>
</li>
<li class="divider"></li>
<li>
<a href="http://www.gitbook.io/" target="blank" class="gitbook-link">Generated using GitBook</a>
</li>
<li style="margin-left:15%;"> <iframe src="http://ghbtns.com/github-btn.html?user=numbbbbb&repo=the-swift-programming-language-in-chinese&type=watch&count=true&size=large"
allowtransparency="true" frameborder="0" scrolling="0" width="170" height="30"></iframe></li>
</ul>
</div>
<div class="book-body">
<div class="body-inner">
<div class="page-wrapper" tabindex="-1">
<div class="book-progress">
<div class="bar">
<div class="inner" style="width: 50%;min-width: 47.36842105263158%;"></div>
</div>
<div class="chapters">
<a href="../index.html" title="Introduction" class="chapter done new-chapter" data-progress="0" style="left: 0%;"></a>
<a href="../chapter1/chapter1.html" title="欢迎使用 Swift" class="chapter done new-chapter" data-progress="1" style="left: 2.6315789473684212%;"></a>
<a href="../chapter1/01_swift.html" title="关于 Swift" class="chapter done " data-progress="1.1" style="left: 5.2631578947368425%;"></a>
<a href="../chapter1/02_a_swift_tour.html" title="Swift 初见" class="chapter done " data-progress="1.2" style="left: 7.894736842105263%;"></a>
<a href="../chapter2/chapter2.html" title="Swift 教程" class="chapter done new-chapter" data-progress="2" style="left: 10.526315789473685%;"></a>
<a href="../chapter2/01_The_Basics.html" title="基础部分" class="chapter done " data-progress="2.1" style="left: 13.157894736842104%;"></a>
<a href="../chapter2/10_Properties.html" title="属性" class="chapter done " data-progress="2.10" style="left: 15.789473684210526%;"></a>
<a href="../chapter2/11_Methods.html" title="方法" class="chapter done " data-progress="2.11" style="left: 18.42105263157895%;"></a>
<a href="../chapter2/12_Subscripts.html" title="附属脚本" class="chapter done " data-progress="2.12" style="left: 21.05263157894737%;"></a>
<a href="../chapter2/13_Inheritance.html" title="继承" class="chapter done " data-progress="2.13" style="left: 23.68421052631579%;"></a>
<a href="../chapter2/14_Initialization.html" title="构造过程" class="chapter done " data-progress="2.14" style="left: 26.31578947368421%;"></a>
<a href="../chapter2/15_Deinitialization.html" title="析构过程" class="chapter done " data-progress="2.15" style="left: 28.94736842105263%;"></a>
<a href="../chapter2/16_Automatic_Reference_Counting.html" title="自动引用计数" class="chapter done " data-progress="2.16" style="left: 31.57894736842105%;"></a>
<a href="../chapter2/17_Optional_Chaining.html" title="可选链" class="chapter done " data-progress="2.17" style="left: 34.21052631578947%;"></a>
<a href="../chapter2/18_Type_Casting.html" title="类型检查" class="chapter done " data-progress="2.18" style="left: 36.8421052631579%;"></a>
<a href="../chapter2/19_Nested_Types.html" title="类型嵌套" class="chapter done " data-progress="2.19" style="left: 39.473684210526315%;"></a>
<a href="../chapter2/02_Basic_Operators.html" title="基本运算符" class="chapter done " data-progress="2.2" style="left: 42.10526315789474%;"></a>
<a href="../chapter2/20_Extensions.html" title="扩展" class="chapter done " data-progress="2.20" style="left: 44.73684210526316%;"></a>
<a href="../chapter2/21_Protocols.html" title="协议" class="chapter done " data-progress="2.21" style="left: 47.36842105263158%;"></a>
<a href="../chapter2/22_Generics.html" title="泛型" class="chapter done " data-progress="2.22" style="left: 50%;"></a>
<a href="../chapter2/23_Advanced_Operators.html" title="高级操作符" class="chapter " data-progress="2.23" style="left: 52.63157894736842%;"></a>
<a href="../chapter2/03_Strings_and_Characters.html" title="字符串和字符" class="chapter " data-progress="2.3" style="left: 55.26315789473684%;"></a>
<a href="../chapter2/04_Collection_Types.html" title="集合类型" class="chapter " data-progress="2.4" style="left: 57.89473684210526%;"></a>
<a href="../chapter2/05_Control_Flow.html" title="控制流" class="chapter " data-progress="2.5" style="left: 60.526315789473685%;"></a>
<a href="../chapter2/06_Functions.html" title="函数" class="chapter " data-progress="2.6" style="left: 63.1578947368421%;"></a>
<a href="../chapter2/07_Closures.html" title="闭包" class="chapter " data-progress="2.7" style="left: 65.78947368421052%;"></a>
<a href="../chapter2/08_Enumerations.html" title="枚举" class="chapter " data-progress="2.8" style="left: 68.42105263157895%;"></a>
<a href="../chapter2/09_Classes_and_Structures.html" title="类和结构体" class="chapter " data-progress="2.9" style="left: 71.05263157894737%;"></a>
<a href="../chapter3/chapter3.html" title="语言参考" class="chapter new-chapter" data-progress="3" style="left: 73.6842105263158%;"></a>
<a href="../chapter3/01_About_the_Language_Reference.html" title="关于语言参考" class="chapter " data-progress="3.1" style="left: 76.3157894736842%;"></a>
<a href="../chapter3/09_Summary_of_the_Grammar.html" title="语法总结" class="chapter " data-progress="3.10" style="left: 78.94736842105263%;"></a>
<a href="../chapter3/02_Lexical_Structure.html" title="词法结构" class="chapter " data-progress="3.2" style="left: 81.57894736842105%;"></a>
<a href="../chapter3/03_Types.html" title="类型" class="chapter " data-progress="3.3" style="left: 84.21052631578948%;"></a>
<a href="../chapter3/04_Expressions.html" title="表达式" class="chapter " data-progress="3.4" style="left: 86.84210526315789%;"></a>
<a href="../chapter3/10_Statements.html" title="语句" class="chapter " data-progress="3.5" style="left: 89.47368421052632%;"></a>
<a href="../chapter3/05_Declarations.html" title="声明" class="chapter " data-progress="3.6" style="left: 92.10526315789474%;"></a>
<a href="../chapter3/06_Attributes.html" title="特性" class="chapter " data-progress="3.7" style="left: 94.73684210526316%;"></a>
<a href="../chapter3/07_Patterns.html" title="模式" class="chapter " data-progress="3.8" style="left: 97.36842105263158%;"></a>
<a href="../chapter3/08_Generic_Parameters_and_Arguments.html" title="泛型参数" class="chapter " data-progress="3.9" style="left: 100%;"></a>
</div>
</div>
<div class="page-inner">
<section class="normal" id="section-gitbook_132">
<blockquote>
<p>翻译:takalard</p>
<p>校对:lifedim</p>
</blockquote>
<h1 id="-">泛型</h1>
<hr>
<p>本页包含内容:</p>
<ul>
<li><a href="#the_problem_that_generics_solve">泛型所解决的问题</a></li>
<li><a href="#generic_functions">泛型函数</a></li>
<li><a href="#type_parameters">类型参数</a></li>
<li><a href="#naming_type_parameters">命名类型参数</a></li>
<li><a href="#generic_types">泛型类型</a></li>
<li><a href="#type_constraints">类型约束</a></li>
<li><a href="#associated_types">关联类型</a></li>
<li><a href="#where_clauses"><code>Where</code>语句</a></li>
</ul>
<p><em>泛型代码</em>可以让你写出根据自我需求定义、适用于任何类型的,灵活且可重用的函数和类型。它的可以让你避免重复的代码,用一种清晰和抽象的方式来表达代码的意图。</p>
<p>泛型是 Swift 强大特征中的其中一个,许多 Swift 标准库是通过泛型代码构建出来的。事实上,泛型的使用贯穿了整本语言手册,只是你没有发现而已。例如,Swift 的数组和字典类型都是泛型集。你可以创建一个<code>Int</code>数组,也可创建一个<code>String</code>数组,或者甚至于可以是任何其他 Swift 的类型数据数组。同样的,你也可以创建存储任何指定类型的字典(dictionary),而且这些类型可以是没有限制的。</p>
<p><a name="the_problem_that_generics_solve"></a></p>
<h2 id="-">泛型所解决的问题</h2>
<p>这里是一个标准的,非泛型函数<code>swapTwoInts</code>,用来交换两个Int值:</p>
<pre><code>func swapTwoInts(inout a: Int, inout b: Int)
let temporaryA = a
a = b
b = temporaryA
}
</code></pre><p>这个函数使用写入读出(in-out)参数来交换<code>a</code>和<code>b</code>的值,请参考[写入读出参数][1]。</p>
<p><code>swapTwoInts</code>函数可以交换<code>b</code>的原始值到<code>a</code>,也可以交换a的原始值到<code>b</code>,你可以调用这个函数交换两个<code>Int</code>变量值:</p>
<pre><code>var someInt = 3
var anotherInt = 107
swapTwoInts(&someInt, &anotherInt)
println("someInt is now \(someInt), and anotherInt is now \(anotherInt)")
// 输出 "someInt is now 107, and anotherInt is now 3"
</code></pre><p><code>swapTwoInts</code>函数是非常有用的,但是它只能交换<code>Int</code>值,如果你想要交换两个<code>String</code>或者<code>Double</code>,就不得不写更多的函数,如 <code>swapTwoStrings</code>和<code>swapTwoDoublesfunctions</code>,如同如下所示:</p>
<pre><code>func swapTwoStrings(inout a: String, inout b: String) {
let temporaryA = a
a = b
b = temporaryA
}
func swapTwoDoubles(inout a: Double, inout b: Double) {
let temporaryA = a
a = b
b = temporaryA
}
</code></pre><p>你可能注意到 <code>swapTwoInts</code>、 <code>swapTwoStrings</code>和<code>swapTwoDoubles</code>函数功能都是相同的,唯一不同之处就在于传入的变量类型不同,分别是<code>Int</code>、<code>String</code>和<code>Double</code>。</p>
<p>但实际应用中通常需要一个用处更强大并且尽可能的考虑到更多的灵活性单个函数,可以用来交换两个任何类型值,很幸运的是,泛型代码帮你解决了这种问题。(一个这种泛型函数后面已经定义好了。)</p>
<blockquote>
<p>注意:
在所有三个函数中,<code>a</code>和<code>b</code>的类型是一样的。如果<code>a</code>和<code>b</code>不是相同的类型,那它们俩就不能互换值。Swift 是类型安全的语言,所以它不允许一个<code>String</code>类型的变量和一个<code>Double</code>类型的变量互相交换值。如果一定要做,Swift 将报编译错误。</p>
</blockquote>
<p><a name="generic_functions"></a></p>
<h2 id="-">泛型函数</h2>
<p><code>泛型函数</code>可以工作于任何类型,这里是一个上面<code>swapTwoInts</code>函数的泛型版本,用于交换两个值:</p>
<pre><code>func swapTwoValues<T>(inout a: T, inout b: T) {
let temporaryA = a
a = b
b = temporaryA
}
</code></pre><p><code>swapTwoValues</code>函数主体和<code>swapTwoInts</code>函数是一样的,它只在第一行稍微有那么一点点不同于<code>swapTwoInts</code>,如下所示:</p>
<pre><code>func swapTwoInts(inout a: Int, inout b: Int)
func swapTwoValues<T>(inout a: T, inout b: T)
</code></pre><p>这个函数的泛型版本使用了占位类型名字(通常此情况下用字母<code>T</code>来表示)来代替实际类型名(如<code>In</code>、<code>String</code>或<code>Doubl</code>)。占位类型名没有提示<code>T</code>必须是什么类型,但是它提示了<code>a</code>和<code>b</code>必须是同一类型<code>T</code>,而不管<code>T</code>表示什么类型。只有<code>swapTwoValues</code>函数在每次调用时所传入的实际类型才能决定<code>T</code>所代表的类型。</p>
<p>另外一个不同之处在于这个泛型函数名后面跟着的展位类型名字(T)是用尖括号括起来的(<T>)。这个尖括号告诉 Swift 那个<code>T</code>是<code>swapTwoValues</code>函数所定义的一个类型。因为<code>T</code>是一个占位命名类型,Swift 不会去查找命名为T的实际类型。</p>
<p><code>swapTwoValues</code>函数除了要求传入的两个任何类型值是同一类型外,也可以作为<code>swapTwoInts</code>函数被调用。每次<code>swapTwoValues</code>被调用,T所代表的类型值都会传给函数。</p>
<p>在下面的两个例子中,<code>T</code>分别代表<code>Int</code>和<code>String</code>:</p>
<pre><code>var someInt = 3
var anotherInt = 107
swapTwoValues(&someInt, &anotherInt)
// someInt is now 107, and anotherInt is now 3
var someString = "hello"
var anotherString = "world"
swapTwoValues(&someString, &anotherString)
// someString is now "world", and anotherString is now "hello"
</code></pre><blockquote>
<p>注意
上面定义的函数<code>swapTwoValues</code>是受<code>swap</code>函数启发而实现的。<code>swap</code>函数存在于 Swift 标准库,并可以在其它类中任意使用。如果你在自己代码中需要类似<code>swapTwoValues</code>函数的功能,你可以使用已存在的交换函数<code>swap</code>函数。</p>
</blockquote>
<p><a name="type_parameters"></a></p>
<h2 id="-">类型参数</h2>
<p>在上面的<code>swapTwoValues</code>例子中,占位类型<code>T</code>是一种类型参数的示例。类型参数指定并命名为一个占位类型,并且紧随在函数名后面,使用一对尖括号括起来(如<T>)。</p>
<p>一旦一个类型参数被指定,那么其可以被使用来定义一个函数的参数类型(如<code>swapTwoValues</code>函数中的参数<code>a</code>和<code>b</code>),或作为一个函数返回类型,或用作函数主体中的注释类型。在这种情况下,被类型参数所代表的占位类型不管函数任何时候被调用,都会被实际类型所替换(在上面<code>swapTwoValues</code>例子中,当函数第一次被调用时,<code>T</code>被<code>Int</code>替换,第二次调用时,被<code>String</code>替换。)。</p>
<p>你可支持多个类型参数,命名在尖括号中,用逗号分开。</p>
<p><a name="naming_type_parameters"></a></p>
<h2 id="-">命名类型参数</h2>
<p>在简单的情况下,泛型函数或泛型类型需要指定一个占位类型(如上面的<code>swapTwoValues</code>泛型函数,或一个存储单一类型的泛型集,如数组),通常用一单个字母<code>T</code>来命名类型参数。不过,你可以使用任何有效的标识符来作为类型参数名。</p>
<p>如果你使用多个参数定义更复杂的泛型函数或泛型类型,那么使用更多的描述类型参数是非常有用的。例如,Swift 字典(Dictionary)类型有两个类型参数,一个是键,另外一个是值。如果你自己写字典,你或许会定义这两个类型参数为<code>KeyType</code>和<code>ValueType</code>,用来记住它们在你的泛型代码中的作用。</p>
<blockquote>
<p>注意
请始终使用大写字母开头的驼峰式命名法(例如<code>T</code>和<code>KeyType</code>)来给类型参数命名,以表明它们是类型的占位符,而非类型值。</p>
</blockquote>
<p><a name="generic_types"></a></p>
<h2 id="-">泛型类型</h2>
<p>通常在泛型函数中,Swift 允许你定义你自己的泛型类型。这些自定义类、结构体和枚举作用于任何类型,如同<code>Array</code>和<code>Dictionary</code>的用法。</p>
<p>这部分向你展示如何写一个泛型集类型--<code>Stack</code>(栈)。一个栈是一系列值域的集合,和<code>Array</code>(数组)类似,但其是一个比 Swift 的<code>Array</code>类型更多限制的集合。一个数组可以允许其里面任何位置的插入/删除操作,而栈,只允许在集合的末端添加新的项(如同<em>push</em>一个新值进栈)。同样的一个栈也只能从末端移除项(如同<em>pop</em>一个值出栈)。</p>
<blockquote>
<p>注意
栈的概念已被<code>UINavigationController</code>类使用来模拟试图控制器的导航结构。你通过调用<code>UINavigationController</code>的<code>pushViewController:animated:</code>方法来为导航栈添加(add)新的试图控制器;而通过<code>popViewControllerAnimated:</code>的方法来从导航栈中移除(pop)某个试图控制器。每当你需要一个严格的<code>后进先出</code>方式来管理集合,堆栈都是最实用的模型。</p>
</blockquote>
<p>下图展示了一个栈的压栈(push)/出栈(pop)的行为:</p>
<p>![此处输入图片的描述][2]</p>
<ol>
<li>现在有三个值在栈中;</li>
<li>第四个值“pushed”到栈的顶部;</li>
<li>现在有四个值在栈中,最近的那个在顶部;</li>
<li>栈中最顶部的那个项被移除,或称之为“popped”;</li>
<li>移除掉一个值后,现在栈又重新只有三个值。</li>
</ol>
<p>这里展示了如何写一个非泛型版本的栈,<code>Int</code>值型的栈:</p>
<pre><code>struct IntStack {
var items = Int[]()
mutating func push(item: Int) {
items.append(item)
}
mutating func pop() -> Int {
return items.removeLast()
}
}
</code></pre><p>这个结构体在栈中使用一个<code>Array</code>性质的<code>items</code>存储值。<code>Stack</code>提供两个方法:<code>push</code>和<code>pop</code>,从栈中压进一个值和移除一个值。这些方法标记为可变的,因为他们需要修改(或<em>转换</em>)结构体的<code>items</code>数组。</p>
<p>上面所展现的<code>IntStack</code>类型只能用于<code>Int</code>值,不过,其对于定义一个泛型<code>Stack</code>类(可以处理<em>任何</em>类型值的栈)是非常有用的。</p>
<p>这里是一个相同代码的泛型版本:</p>
<pre><code>struct Stack<T> {
var items = T[]()
mutating func push(item: T) {
items.append(item)
}
mutating func pop() -> T {
return items.removeLast()
}
}
</code></pre><p>注意到<code>Stack</code>的泛型版本基本上和非泛型版本相同,但是泛型版本的占位类型参数为T代替了实际<code>Int</code>类型。这种类型参数包含在一对尖括号里(<code><T></code>),紧随在结构体名字后面。</p>
<p><code>T</code>定义了一个名为“某种类型T”的节点提供给后来用。这种将来类型可以在结构体的定义里任何地方表示为“T”。在这种情况下,<code>T</code>在如下三个地方被用作节点:</p>
<ul>
<li>创建一个名为<code>items</code>的属性,使用空的T类型值数组对其进行初始化;</li>
<li>指定一个包含一个参数名为<code>item</code>的<code>push</code>方法,该参数必须是T类型;</li>
<li>指定一个<code>pop</code>方法的返回值,该返回值将是一个T类型值。</li>
</ul>
<p>当创建一个新单例并初始化时, 通过用一对紧随在类型名后的尖括号里写出实际指定栈用到类型,创建一个<code>Stack</code>实例,同创建<code>Array</code>和<code>Dictionary</code>一样:</p>
<pre><code>var stackOfStrings = Stack<String>()
stackOfStrings.push("uno")
stackOfStrings.push("dos")
stackOfStrings.push("tres")
stackOfStrings.push("cuatro")
// 现在栈已经有4个string了
</code></pre><p>下图将展示<code>stackOfStrings</code>如何<code>push</code>这四个值进栈的过程:</p>
<p>![此处输入图片的描述][3]</p>
<p>从栈中<code>pop</code>并移除值"cuatro":</p>
<pre><code>let fromTheTop = stackOfStrings.pop()
// fromTheTop is equal to "cuatro", and the stack now contains 3 strings
</code></pre><p>下图展示了如何从栈中pop一个值的过程:
![此处输入图片的描述][4]</p>
<p>由于<code>Stack</code>是泛型类型,所以在 Swift 中其可以用来创建任何有效类型的栈,这种方式如同<code>Array</code>和<code>Dictionary</code>。</p>
<p><a name="type_constraints"></a></p>
<h2 id="-">类型约束</h2>
<p><code>swapTwoValues</code>函数和<code>Stack</code>类型可以作用于任何类型,不过,有的时候对使用在泛型函数和泛型类型上的类型强制约束为某种特定类型是非常有用的。类型约束指定了一个必须继承自指定类的类型参数,或者遵循一个特定的协议或协议构成。</p>
<p>例如,Swift 的<code>Dictionary</code>类型对作用于其键的类型做了些限制。在[字典][5]的描述中,字典的键类型必须是<em>可哈希</em>,也就是说,必须有一种方法可以使其是唯一的表示。<code>Dictionary</code>之所以需要其键是可哈希是为了以便于其检查其是否包含某个特定键的值。如无此需求,<code>Dictionary</code>即不会告诉是否插入或者替换了某个特定键的值,也不能查找到已经存储在字典里面的给定键值。</p>
<p>这个需求强制加上一个类型约束作用于<code>Dictionary</code>的键上,当然其键类型必须遵循<code>Hashable</code>协议(Swift 标准库中定义的一个特定协议)。所有的 Swift 基本类型(如<code>String</code>,<code>Int</code>, <code>Double</code>和 <code>Bool</code>)默认都是可哈希。</p>
<p>当你创建自定义泛型类型时,你可以定义你自己的类型约束,当然,这些约束要支持泛型编程的强力特征中的多数。抽象概念如<code>可哈希</code>具有的类型特征是根据他们概念特征来界定的,而不是他们的直接类型特征。</p>
<h3 id="-">类型约束语法</h3>
<p>你可以写一个在一个类型参数名后面的类型约束,通过冒号分割,来作为类型参数链的一部分。这种作用于泛型函数的类型约束的基础语法如下所示(和泛型类型的语法相同):</p>
<pre><code>func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) {
// function body goes here
}
</code></pre><p>上面这个假定函数有两个类型参数。第一个类型参数<code>T</code>,有一个需要<code>T</code>必须是<code>SomeClass</code>子类的类型约束;第二个类型参数<code>U</code>,有一个需要<code>U</code>必须遵循<code>SomeProtocol</code>协议的类型约束。</p>
<h3 id="-">类型约束行为</h3>
<p>这里有个名为<code>findStringIndex</code>的非泛型函数,该函数功能是去查找包含一给定<code>String</code>值的数组。若查找到匹配的字符串,<code>findStringIndex</code>函数返回该字符串在数组中的索引值(<code>Int</code>),反之则返回<code>nil</code>:</p>
<pre><code>func findStringIndex(array: String[], valueToFind: String) -> Int? {
for (index, value) in enumerate(array) {
if value == valueToFind {
return index
}
}
return nil
}
</code></pre><p><code>findStringIndex</code>函数可以作用于查找一字符串数组中的某个字符串:</p>
<pre><code>let strings = ["cat", "dog", "llama", "parakeet", "terrapin"]
if let foundIndex = findStringIndex(strings, "llama") {
println("The index of llama is \(foundIndex)")
}
// 输出 "The index of llama is 2"
</code></pre><p>如果只是针对字符串而言查找在数组中的某个值的索引,用处不是很大,不过,你可以写出相同功能的泛型函数<code>findIndex</code>,用某个类型<code>T</code>值替换掉提到的字符串。</p>
<p>这里展示如何写一个你或许期望的<code>findStringIndex</code>的泛型版本<code>findIndex</code>。请注意这个函数仍然返回<code>Int</code>,是不是有点迷惑呢,而不是泛型类型?那是因为函数返回的是一个可选的索引数,而不是从数组中得到的一个可选值。需要提醒的是,这个函数不会编译,原因在例子后面会说明:</p>
<pre><code>func findIndex<T>(array: T[], valueToFind: T) -> Int? {
for (index, value) in enumerate(array) {
if value == valueToFind {
return index
}
}
return nil
}
</code></pre><p>上面所写的函数不会编译。这个问题的位置在等式的检查上,<code>“if value == valueToFind”</code>。不是所有的 Swift 中的类型都可以用等式符(==)进行比较。例如,如果你创建一个你自己的类或结构体来表示一个复杂的数据模型,那么 Swift 没法猜到对于这个类或结构体而言“等于”的意思。正因如此,这部分代码不能可能保证工作于每个可能的类型<code>T</code>,当你试图编译这部分代码时估计会出现相应的错误。</p>
<p>不过,所有的这些并不会让我们无从下手。Swift 标准库中定义了一个<code>Equatable</code>协议,该协议要求任何遵循的类型实现等式符(==)和不等符(!=)对任何两个该类型进行比较。所有的 Swift 标准类型自动支持<code>Equatable</code>协议。</p>
<p>任何<code>Equatable</code>类型都可以安全的使用在<code>findIndex</code>函数中,因为其保证支持等式操作。为了说明这个事实,当你定义一个函数时,你可以写一个<code>Equatable</code>类型约束作为类型参数定义的一部分:</p>
<pre><code>func findIndex<T: Equatable>(array: T[], valueToFind: T) -> Int? {
for (index, value) in enumerate(array) {
if value == valueToFind {
return index
}
}
return nil
}
</code></pre><p><code>findIndex</code>中这个单个类型参数写做:<code>T: Equatable</code>,也就意味着“任何T类型都遵循<code>Equatable</code>协议”。</p>
<p><code>findIndex</code>函数现在则可以成功的编译过,并且作用于任何遵循<code>Equatable</code>的类型,如<code>Double</code>或<code>String</code>:</p>
<pre><code>let doubleIndex = findIndex([3.14159, 0.1, 0.25], 9.3)
// doubleIndex is an optional Int with no value, because 9.3 is not in the array
let stringIndex = findIndex(["Mike", "Malcolm", "Andrea"], "Andrea")
// stringIndex is an optional Int containing a value of 2
</code></pre><p><a name="associated_types"></a></p>
<h2 id="-">关联类型</h2>
<p>当定义一个协议时,有的时候声明一个或多个关联类型作为协议定义的一部分是非常有用的。一个关联类型给定作用于协议部分的类型一个节点名(或<em>别名</em>)。作用于关联类型上实际类型是不需要指定的,直到该协议接受。关联类型被指定为<code>typealias</code>关键字。</p>
<h3 id="-">关联类型行为</h3>
<p>这里是一个<code>Container</code>协议的例子,定义了一个ItemType关联类型:</p>
<pre><code>protocol Container {
typealias ItemType
mutating func append(item: ItemType)
var count: Int { get }
subscript(i: Int) -> ItemType { get }
}
</code></pre><p><code>Container</code>协议定义了三个任何容器必须支持的兼容要求:</p>
<ul>
<li>必须可能通过<code>append</code>方法添加一个新item到容器里;</li>
<li>必须可能通过使用<code>count</code>属性获取容器里items的数量,并返回一个<code>Int</code>值;</li>
<li>必须可能通过容器的<code>Int</code>索引值下标可以检索到每一个item。</li>
</ul>
<p>这个协议没有指定容器里item是如何存储的或何种类型是允许的。这个协议只指定三个任何遵循<code>Container</code>类型所必须支持的功能点。一个遵循的类型也可以提供其他额外的功能,只要满足这三个条件。</p>
<p>任何遵循<code>Container</code>协议的类型必须指定存储在其里面的值类型,必须保证只有正确类型的items可以加进容器里,必须明确可以通过其下标返回item类型。</p>
<p>为了定义这三个条件,<code>Container</code>协议需要一个方法指定容器里的元素将会保留,而不需要知道特定容器的类型。<code>Container</code>协议需要指定任何通过<code>append</code>方法添加到容器里的值和容器里元素是相同类型,并且通过容器下标返回的容器元素类型的值的类型是相同类型。</p>
<p>为了达到此目的,<code>Container</code>协议声明了一个ItemType的关联类型,写作<code>typealias ItemType</code>。The protocol does not define what ItemType is an alias for—that information is left for any conforming type to provide(这个协议不会定义<code>ItemType</code>是遵循类型所提供的何种信息的别名)。尽管如此,<code>ItemType</code>别名支持一种方法识别在一个容器里的items类型,以及定义一种使用在<code>append</code>方法和下标中的类型,以便保证任何期望的<code>Container</code>的行为是强制性的。</p>
<p>这里是一个早前IntStack类型的非泛型版本,适用于遵循Container协议:</p>
<pre><code>struct IntStack: Container {
// original IntStack implementation
var items = Int[]()
mutating func push(item: Int) {
items.append(item)
}
mutating func pop() -> Int {
return items.removeLast()
}
// conformance to the Container protocol
typealias ItemType = Int
mutating func append(item: Int) {
self.push(item)
}
var count: Int {
return items.count
}
subscript(i: Int) -> Int {
return items[i]
}
}
</code></pre><p><code>IntStack</code>类型实现了<code>Container</code>协议的所有三个要求,在<code>IntStack</code>类型的每个包含部分的功能都满足这些要求。</p>
<p>此外,<code>IntStack</code>指定了<code>Container</code>的实现,适用的ItemType被用作<code>Int</code>类型。对于这个<code>Container</code>协议实现而言,定义 <code>typealias ItemType = Int</code>,将抽象的<code>ItemType</code>类型转换为具体的<code>Int</code>类型。</p>
<p>感谢Swift类型参考,你不用在<code>IntStack</code>定义部分声明一个具体的<code>Int</code>的<code>ItemType</code>。由于<code>IntStack</code>遵循<code>Container</code>协议的所有要求,只要通过简单的查找<code>append</code>方法的item参数类型和下标返回的类型,Swift就可以推断出合适的<code>ItemType</code>来使用。确实,如果上面的代码中你删除了 <code>typealias ItemType = Int</code>这一行,一切仍旧可以工作,因为它清楚的知道ItemType使用的是何种类型。</p>
<p>你也可以生成遵循<code>Container</code>协议的泛型<code>Stack</code>类型:</p>
<pre><code>struct Stack<T>: Container {
// original Stack<T> implementation
var items = T[]()
mutating func push(item: T) {
items.append(item)
}
mutating func pop() -> T {
return items.removeLast()
}
// conformance to the Container protocol
mutating func append(item: T) {
self.push(item)
}
var count: Int {
return items.count
}
subscript(i: Int) -> T {
return items[i]
}
}
</code></pre><p>这个时候,占位类型参数<code>T</code>被用作<code>append</code>方法的item参数和下标的返回类型。Swift 因此可以推断出被用作这个特定容器的<code>ItemType</code>的<code>T</code>的合适类型。</p>
<h3 id="-">扩展一个存在的类型为一指定关联类型</h3>
<p>在[使用扩展来添加协议兼容性][6]中有描述扩展一个存在的类型添加遵循一个协议。这个类型包含一个关联类型的协议。</p>
<p>Swift的<code>Array</code>已经提供<code>append</code>方法,一个<code>count</code>属性和通过下标来查找一个自己的元素。这三个功能都达到<code>Container</code>协议的要求。也就意味着你可以扩展<code>Array</code>去遵循<code>Container</code>协议,只要通过简单声明<code>Array</code>适用于该协议而已。如何实践这样一个空扩展,在[使用扩展来声明协议的采纳][7]中有描述这样一个实现一个空扩展的行为:</p>
<pre><code>extension Array: Container {}
</code></pre><p>如同上面的泛型<code>Stack</code>类型一样,<code>Array的append</code>方法和下标保证<code>Swift</code>可以推断出<code>ItemType</code>所使用的适用的类型。定义了这个扩展后,你可以将任何<code>Array</code>当作<code>Container</code>来使用。</p>
<p><a name="where_clauses"></a></p>
<h2 id="where-">Where 语句</h2>
<p>[类型约束][8]中描述的类型约束确保你定义关于类型参数的需求和一泛型函数或类型有关联。</p>
<p>对于关联类型的定义需求也是非常有用的。你可以通过这样去定义<em>where语句</em>作为一个类型参数队列的一部分。一个<code>where</code>语句使你能够要求一个关联类型遵循一个特定的协议,以及(或)那个特定的类型参数和关联类型可以是相同的。你可写一个<code>where</code>语句,通过紧随放置<code>where</code>关键字在类型参数队列后面,其后跟着一个或者多个针对关联类型的约束,以及(或)一个或多个类型和关联类型的等于关系。</p>
<p>下面的列子定义了一个名为<code>allItemsMatch</code>的泛型函数,用来检查是否两个<code>Container</code>单例包含具有相同顺序的相同元素。如果匹配到所有的元素,那么返回一个为<code>true</code>的<code>Boolean</code>值,反之,则相反。</p>
<p>这两个容器可以被检查出是否是相同类型的容器(虽然它们可以是),但他们确实拥有相同类型的元素。这个需求通过一个类型约束和<code>where</code>语句结合来表示:</p>
<pre><code>func allItemsMatch<
C1: Container, C2: Container
where C1.ItemType == C2.ItemType, C1.ItemType: Equatable>
(someContainer: C1, anotherContainer: C2) -> Bool {
// check that both containers contain the same number of items
if someContainer.count != anotherContainer.count {
return false
}
// check each pair of items to see if they are equivalent
for i in 0..someContainer.count {
if someContainer[i] != anotherContainer[i] {
return false
}
}
// all items match, so return true
return true
}
</code></pre><p>这个函数用了两个参数:<code>someContainer</code>和<code>anotherContainer</code>。<code>someContainer</code>参数是类型<code>C1</code>,<code>anotherContainer</code>参数是类型<code>C2</code>。<code>C1</code>和<code>C2</code>是容器的两个占位类型参数,决定了这个函数何时被调用。</p>
<p>这个函数的类型参数列紧随在两个类型参数需求的后面:</p>
<ul>
<li><code>C1</code>必须遵循<code>Container</code>协议 (写作 <code>C1: Container</code>)。</li>
<li><code>C2</code>必须遵循<code>Container</code>协议 (写作 <code>C2: Container</code>)。</li>
<li><code>C1</code>的<code>ItemType</code>同样是C2的<code>ItemType</code>(写作 <code>C1.ItemType == C2.ItemType</code>)。</li>
<li><code>C1</code>的<code>ItemType</code>必须遵循<code>Equatable</code>协议 (写作 <code>C1.ItemType: Equatable</code>)。</li>
</ul>
<p>第三个和第四个要求被定义为一个<code>where</code>语句的一部分,写在关键字<code>where</code>后面,作为函数类型参数链的一部分。</p>
<p>这些要求意思是:</p>
<p><code>someContainer</code>是一个<code>C1</code>类型的容器。
<code>anotherContainer</code>是一个<code>C2</code>类型的容器。
<code>someContainer</code>和<code>anotherContainer</code>包含相同的元素类型。
<code>someContainer</code>中的元素可以通过不等于操作(<code>!=</code>)来检查它们是否彼此不同。</p>
<p>第三个和第四个要求结合起来的意思是<code>anotherContainer</code>中的元素也可以通过 <code>!=</code> 操作来检查,因为他们在<code>someContainer</code>中元素确实是相同的类型。</p>
<p>这些要求能够使<code>allItemsMatch</code>函数比较两个容器,即便他们是不同的容器类型。</p>
<p><code>allItemsMatch</code>首先检查两个容器是否拥有同样数目的items,如果他们的元素数目不同,没有办法进行匹配,函数就会<code>false</code>。</p>
<p>检查完之后,函数通过<code>for-in</code>循环和半闭区间操作(..)来迭代<code>someContainer</code>中的所有元素。对于每个元素,函数检查是否<code>someContainer</code>中的元素不等于对应的<code>anotherContainer</code>中的元素,如果这两个元素不等,则这两个容器不匹配,返回<code>false</code>。</p>
<p>如果循环体结束后未发现没有任何的不匹配,那表明两个容器匹配,函数返回<code>true</code>。</p>
<p>这里演示了allItemsMatch函数运算的过程:</p>
<pre><code>var stackOfStrings = Stack<String>()
stackOfStrings.push("uno")
stackOfStrings.push("dos")
stackOfStrings.push("tres")
var arrayOfStrings = ["uno", "dos", "tres"]
if allItemsMatch(stackOfStrings, arrayOfStrings) {
println("All items match.")
} else {
println("Not all items match.")
}
// 输出 "All items match."
</code></pre><p> 上面的例子创建一个<code>Stack</code>单例来存储<code>String</code>,然后压了三个字符串进栈。这个例子也创建了一个<code>Array</code>单例,并初始化包含三个同栈里一样的原始字符串。即便栈和数组否是不同的类型,但他们都遵循<code>Container</code>协议,而且他们都包含同样的类型值。你因此可以调用<code>allItemsMatch</code>函数,用这两个容器作为它的参数。在上面的例子中,<code>allItemsMatch</code>函数正确的显示了所有的这两个容器的<code>items</code>匹配。</p>
</section>
</div>
</div>
</div>
<a href="../chapter2/21_Protocols.html" class="navigation navigation-prev " aria-label="Previous page: 协议"><i class="fa fa-angle-left"></i></a>
<a href="../chapter2/23_Advanced_Operators.html" class="navigation navigation-next " aria-label="Next page: 高级操作符"><i class="fa fa-angle-right"></i></a>
</div>
</div>
<script src="http://cdn.bootcss.com/ace/1.1.3/ace.js"></script>
<script src="http://cdn.bootcss.com/ace/1.1.3/mode-javascript.js"></script>
<script src="../gitbook/jsrepl/jsrepl.js" id="jsrepl-script"></script>
<script src="../gitbook/app.js"></script>
<script src="../gitbook/plugins/gitbook-plugin-mixpanel/plugin.js"></script>
<script src="http://cdn.mathjax.org/mathjax/2.0-latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
<script src="../gitbook/plugins/gitbook-plugin-mathjax/plugin.js"></script>
<script>
require(["gitbook"], function(gitbook) {
var config = {};
gitbook.start(config);
});
</script>
<script src="http://s19.cnzz.com/z_stat.php?id=1000480711&web_id=1000480711" language="JavaScript"></script></body>
</html>