-
Notifications
You must be signed in to change notification settings - Fork 1
/
ch2-types.html
1745 lines (1702 loc) · 96.4 KB
/
ch2-types.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
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=edge"><![endif]-->
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="generator" content="Asciidoctor 1.5.2">
<title>Working with types</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400">
<style>
/* Asciidoctor default stylesheet | MIT License | http://asciidoctor.org */
/* Remove the comments around the @import statement below when using this as a custom stylesheet */
/*@import "https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400";*/
article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}
audio,canvas,video{display:inline-block}
audio:not([controls]){display:none;height:0}
[hidden],template{display:none}
script{display:none!important}
html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}
body{margin:0}
a{background:transparent}
a:focus{outline:thin dotted}
a:active,a:hover{outline:0}
h1{font-size:2em;margin:.67em 0}
abbr[title]{border-bottom:1px dotted}
b,strong{font-weight:bold}
dfn{font-style:italic}
hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}
mark{background:#ff0;color:#000}
code,kbd,pre,samp{font-family:monospace;font-size:1em}
pre{white-space:pre-wrap}
q{quotes:"\201C" "\201D" "\2018" "\2019"}
small{font-size:80%}
sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}
sup{top:-.5em}
sub{bottom:-.25em}
img{border:0}
svg:not(:root){overflow:hidden}
figure{margin:0}
fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}
legend{border:0;padding:0}
button,input,select,textarea{font-family:inherit;font-size:100%;margin:0}
button,input{line-height:normal}
button,select{text-transform:none}
button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}
button[disabled],html input[disabled]{cursor:default}
input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}
input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}
input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}
button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}
textarea{overflow:auto;vertical-align:top}
table{border-collapse:collapse;border-spacing:0}
*,*:before,*:after{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}
html,body{font-size:100%}
body{background:#fff;color:rgba(0,0,0,.8);padding:0;margin:0;font-family:"Noto Serif","DejaVu Serif",serif;font-weight:400;font-style:normal;line-height:1;position:relative;cursor:auto}
a:hover{cursor:pointer}
img,object,embed{max-width:100%;height:auto}
object,embed{height:100%}
img{-ms-interpolation-mode:bicubic}
#map_canvas img,#map_canvas embed,#map_canvas object,.map_canvas img,.map_canvas embed,.map_canvas object{max-width:none!important}
.left{float:left!important}
.right{float:right!important}
.text-left{text-align:left!important}
.text-right{text-align:right!important}
.text-center{text-align:center!important}
.text-justify{text-align:justify!important}
.hide{display:none}
.antialiased,body{-webkit-font-smoothing:antialiased}
img{display:inline-block;vertical-align:middle}
textarea{height:auto;min-height:50px}
select{width:100%}
p.lead,.paragraph.lead>p,#preamble>.sectionbody>.paragraph:first-of-type p{font-size:1.21875em;line-height:1.6}
.subheader,.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{line-height:1.45;color:#7a2518;font-weight:400;margin-top:0;margin-bottom:.25em}
div,dl,dt,dd,ul,ol,li,h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6,pre,form,p,blockquote,th,td{margin:0;padding:0;direction:ltr}
a{color:#2156a5;text-decoration:underline;line-height:inherit}
a:hover,a:focus{color:#1d4b8f}
a img{border:none}
p{font-family:inherit;font-weight:400;font-size:1em;line-height:1.6;margin-bottom:1.25em;text-rendering:optimizeLegibility}
p aside{font-size:.875em;line-height:1.35;font-style:italic}
h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{font-family:"Open Sans","DejaVu Sans",sans-serif;font-weight:300;font-style:normal;color:#ba3925;text-rendering:optimizeLegibility;margin-top:1em;margin-bottom:.5em;line-height:1.0125em}
h1 small,h2 small,h3 small,#toctitle small,.sidebarblock>.content>.title small,h4 small,h5 small,h6 small{font-size:60%;color:#e99b8f;line-height:0}
h1{font-size:2.125em}
h2{font-size:1.6875em}
h3,#toctitle,.sidebarblock>.content>.title{font-size:1.375em}
h4,h5{font-size:1.125em}
h6{font-size:1em}
hr{border:solid #ddddd8;border-width:1px 0 0;clear:both;margin:1.25em 0 1.1875em;height:0}
em,i{font-style:italic;line-height:inherit}
strong,b{font-weight:bold;line-height:inherit}
small{font-size:60%;line-height:inherit}
code{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;font-weight:400;color:rgba(0,0,0,.9)}
ul,ol,dl{font-size:1em;line-height:1.6;margin-bottom:1.25em;list-style-position:outside;font-family:inherit}
ul,ol,ul.no-bullet,ol.no-bullet{margin-left:1.5em}
ul li ul,ul li ol{margin-left:1.25em;margin-bottom:0;font-size:1em}
ul.square li ul,ul.circle li ul,ul.disc li ul{list-style:inherit}
ul.square{list-style-type:square}
ul.circle{list-style-type:circle}
ul.disc{list-style-type:disc}
ul.no-bullet{list-style:none}
ol li ul,ol li ol{margin-left:1.25em;margin-bottom:0}
dl dt{margin-bottom:.3125em;font-weight:bold}
dl dd{margin-bottom:1.25em}
abbr,acronym{text-transform:uppercase;font-size:90%;color:rgba(0,0,0,.8);border-bottom:1px dotted #ddd;cursor:help}
abbr{text-transform:none}
blockquote{margin:0 0 1.25em;padding:.5625em 1.25em 0 1.1875em;border-left:1px solid #ddd}
blockquote cite{display:block;font-size:.9375em;color:rgba(0,0,0,.6)}
blockquote cite:before{content:"\2014 \0020"}
blockquote cite a,blockquote cite a:visited{color:rgba(0,0,0,.6)}
blockquote,blockquote p{line-height:1.6;color:rgba(0,0,0,.85)}
@media only screen and (min-width:768px){h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2}
h1{font-size:2.75em}
h2{font-size:2.3125em}
h3,#toctitle,.sidebarblock>.content>.title{font-size:1.6875em}
h4{font-size:1.4375em}}table{background:#fff;margin-bottom:1.25em;border:solid 1px #dedede}
table thead,table tfoot{background:#f7f8f7;font-weight:bold}
table thead tr th,table thead tr td,table tfoot tr th,table tfoot tr td{padding:.5em .625em .625em;font-size:inherit;color:rgba(0,0,0,.8);text-align:left}
table tr th,table tr td{padding:.5625em .625em;font-size:inherit;color:rgba(0,0,0,.8)}
table tr.even,table tr.alt,table tr:nth-of-type(even){background:#f8f8f7}
table thead tr th,table tfoot tr th,table tbody tr td,table tr td,table tfoot tr td{display:table-cell;line-height:1.6}
h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2;word-spacing:-.05em}
h1 strong,h2 strong,h3 strong,#toctitle strong,.sidebarblock>.content>.title strong,h4 strong,h5 strong,h6 strong{font-weight:400}
.clearfix:before,.clearfix:after,.float-group:before,.float-group:after{content:" ";display:table}
.clearfix:after,.float-group:after{clear:both}
*:not(pre)>code{font-size:.9375em;font-style:normal!important;letter-spacing:0;padding:.1em .5ex;word-spacing:-.15em;background-color:#f7f7f8;-webkit-border-radius:4px;border-radius:4px;line-height:1.45;text-rendering:optimizeSpeed}
pre,pre>code{line-height:1.45;color:rgba(0,0,0,.9);font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;font-weight:400;text-rendering:optimizeSpeed}
.keyseq{color:rgba(51,51,51,.8)}
kbd{display:inline-block;color:rgba(0,0,0,.8);font-size:.75em;line-height:1.4;background-color:#f7f7f7;border:1px solid #ccc;-webkit-border-radius:3px;border-radius:3px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,.2),0 0 0 .1em white inset;box-shadow:0 1px 0 rgba(0,0,0,.2),0 0 0 .1em #fff inset;margin:-.15em .15em 0 .15em;padding:.2em .6em .2em .5em;vertical-align:middle;white-space:nowrap}
.keyseq kbd:first-child{margin-left:0}
.keyseq kbd:last-child{margin-right:0}
.menuseq,.menu{color:rgba(0,0,0,.8)}
b.button:before,b.button:after{position:relative;top:-1px;font-weight:400}
b.button:before{content:"[";padding:0 3px 0 2px}
b.button:after{content:"]";padding:0 2px 0 3px}
p a>code:hover{color:rgba(0,0,0,.9)}
#header,#content,#footnotes,#footer{width:100%;margin-left:auto;margin-right:auto;margin-top:0;margin-bottom:0;max-width:62.5em;*zoom:1;position:relative;padding-left:.9375em;padding-right:.9375em}
#header:before,#header:after,#content:before,#content:after,#footnotes:before,#footnotes:after,#footer:before,#footer:after{content:" ";display:table}
#header:after,#content:after,#footnotes:after,#footer:after{clear:both}
#content{margin-top:1.25em}
#content:before{content:none}
#header>h1:first-child{color:rgba(0,0,0,.85);margin-top:2.25rem;margin-bottom:0}
#header>h1:first-child+#toc{margin-top:8px;border-top:1px solid #ddddd8}
#header>h1:only-child,body.toc2 #header>h1:nth-last-child(2){border-bottom:1px solid #ddddd8;padding-bottom:8px}
#header .details{border-bottom:1px solid #ddddd8;line-height:1.45;padding-top:.25em;padding-bottom:.25em;padding-left:.25em;color:rgba(0,0,0,.6);display:-ms-flexbox;display:-webkit-flex;display:flex;-ms-flex-flow:row wrap;-webkit-flex-flow:row wrap;flex-flow:row wrap}
#header .details span:first-child{margin-left:-.125em}
#header .details span.email a{color:rgba(0,0,0,.85)}
#header .details br{display:none}
#header .details br+span:before{content:"\00a0\2013\00a0"}
#header .details br+span.author:before{content:"\00a0\22c5\00a0";color:rgba(0,0,0,.85)}
#header .details br+span#revremark:before{content:"\00a0|\00a0"}
#header #revnumber{text-transform:capitalize}
#header #revnumber:after{content:"\00a0"}
#content>h1:first-child:not([class]){color:rgba(0,0,0,.85);border-bottom:1px solid #ddddd8;padding-bottom:8px;margin-top:0;padding-top:1rem;margin-bottom:1.25rem}
#toc{border-bottom:1px solid #efefed;padding-bottom:.5em}
#toc>ul{margin-left:.125em}
#toc ul.sectlevel0>li>a{font-style:italic}
#toc ul.sectlevel0 ul.sectlevel1{margin:.5em 0}
#toc ul{font-family:"Open Sans","DejaVu Sans",sans-serif;list-style-type:none}
#toc a{text-decoration:none}
#toc a:active{text-decoration:underline}
#toctitle{color:#7a2518;font-size:1.2em}
@media only screen and (min-width:768px){#toctitle{font-size:1.375em}
body.toc2{padding-left:15em;padding-right:0}
#toc.toc2{margin-top:0!important;background-color:#f8f8f7;position:fixed;width:15em;left:0;top:0;border-right:1px solid #efefed;border-top-width:0!important;border-bottom-width:0!important;z-index:1000;padding:1.25em 1em;height:100%;overflow:auto}
#toc.toc2 #toctitle{margin-top:0;font-size:1.2em}
#toc.toc2>ul{font-size:.9em;margin-bottom:0}
#toc.toc2 ul ul{margin-left:0;padding-left:1em}
#toc.toc2 ul.sectlevel0 ul.sectlevel1{padding-left:0;margin-top:.5em;margin-bottom:.5em}
body.toc2.toc-right{padding-left:0;padding-right:15em}
body.toc2.toc-right #toc.toc2{border-right-width:0;border-left:1px solid #efefed;left:auto;right:0}}@media only screen and (min-width:1280px){body.toc2{padding-left:20em;padding-right:0}
#toc.toc2{width:20em}
#toc.toc2 #toctitle{font-size:1.375em}
#toc.toc2>ul{font-size:.95em}
#toc.toc2 ul ul{padding-left:1.25em}
body.toc2.toc-right{padding-left:0;padding-right:20em}}#content #toc{border-style:solid;border-width:1px;border-color:#e0e0dc;margin-bottom:1.25em;padding:1.25em;background:#f8f8f7;-webkit-border-radius:4px;border-radius:4px}
#content #toc>:first-child{margin-top:0}
#content #toc>:last-child{margin-bottom:0}
#footer{max-width:100%;background-color:rgba(0,0,0,.8);padding:1.25em}
#footer-text{color:rgba(255,255,255,.8);line-height:1.44}
.sect1{padding-bottom:.625em}
@media only screen and (min-width:768px){.sect1{padding-bottom:1.25em}}.sect1+.sect1{border-top:1px solid #efefed}
#content h1>a.anchor,h2>a.anchor,h3>a.anchor,#toctitle>a.anchor,.sidebarblock>.content>.title>a.anchor,h4>a.anchor,h5>a.anchor,h6>a.anchor{position:absolute;z-index:1001;width:1.5ex;margin-left:-1.5ex;display:block;text-decoration:none!important;visibility:hidden;text-align:center;font-weight:400}
#content h1>a.anchor:before,h2>a.anchor:before,h3>a.anchor:before,#toctitle>a.anchor:before,.sidebarblock>.content>.title>a.anchor:before,h4>a.anchor:before,h5>a.anchor:before,h6>a.anchor:before{content:"\00A7";font-size:.85em;display:block;padding-top:.1em}
#content h1:hover>a.anchor,#content h1>a.anchor:hover,h2:hover>a.anchor,h2>a.anchor:hover,h3:hover>a.anchor,#toctitle:hover>a.anchor,.sidebarblock>.content>.title:hover>a.anchor,h3>a.anchor:hover,#toctitle>a.anchor:hover,.sidebarblock>.content>.title>a.anchor:hover,h4:hover>a.anchor,h4>a.anchor:hover,h5:hover>a.anchor,h5>a.anchor:hover,h6:hover>a.anchor,h6>a.anchor:hover{visibility:visible}
#content h1>a.link,h2>a.link,h3>a.link,#toctitle>a.link,.sidebarblock>.content>.title>a.link,h4>a.link,h5>a.link,h6>a.link{color:#ba3925;text-decoration:none}
#content h1>a.link:hover,h2>a.link:hover,h3>a.link:hover,#toctitle>a.link:hover,.sidebarblock>.content>.title>a.link:hover,h4>a.link:hover,h5>a.link:hover,h6>a.link:hover{color:#a53221}
.audioblock,.imageblock,.literalblock,.listingblock,.stemblock,.videoblock{margin-bottom:1.25em}
.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{text-rendering:optimizeLegibility;text-align:left;font-family:"Noto Serif","DejaVu Serif",serif;font-size:1rem;font-style:italic}
table.tableblock>caption.title{white-space:nowrap;overflow:visible;max-width:0}
.paragraph.lead>p,#preamble>.sectionbody>.paragraph:first-of-type p{color:rgba(0,0,0,.85)}
table.tableblock #preamble>.sectionbody>.paragraph:first-of-type p{font-size:inherit}
.admonitionblock>table{border-collapse:separate;border:0;background:none;width:100%}
.admonitionblock>table td.icon{text-align:center;width:80px}
.admonitionblock>table td.icon img{max-width:none}
.admonitionblock>table td.icon .title{font-weight:bold;font-family:"Open Sans","DejaVu Sans",sans-serif;text-transform:uppercase}
.admonitionblock>table td.content{padding-left:1.125em;padding-right:1.25em;border-left:1px solid #ddddd8;color:rgba(0,0,0,.6)}
.admonitionblock>table td.content>:last-child>:last-child{margin-bottom:0}
.exampleblock>.content{border-style:solid;border-width:1px;border-color:#e6e6e6;margin-bottom:1.25em;padding:1.25em;background:#fff;-webkit-border-radius:4px;border-radius:4px}
.exampleblock>.content>:first-child{margin-top:0}
.exampleblock>.content>:last-child{margin-bottom:0}
.sidebarblock{border-style:solid;border-width:1px;border-color:#e0e0dc;margin-bottom:1.25em;padding:1.25em;background:#f8f8f7;-webkit-border-radius:4px;border-radius:4px}
.sidebarblock>:first-child{margin-top:0}
.sidebarblock>:last-child{margin-bottom:0}
.sidebarblock>.content>.title{color:#7a2518;margin-top:0;text-align:center}
.exampleblock>.content>:last-child>:last-child,.exampleblock>.content .olist>ol>li:last-child>:last-child,.exampleblock>.content .ulist>ul>li:last-child>:last-child,.exampleblock>.content .qlist>ol>li:last-child>:last-child,.sidebarblock>.content>:last-child>:last-child,.sidebarblock>.content .olist>ol>li:last-child>:last-child,.sidebarblock>.content .ulist>ul>li:last-child>:last-child,.sidebarblock>.content .qlist>ol>li:last-child>:last-child{margin-bottom:0}
.literalblock pre,.listingblock pre:not(.highlight),.listingblock pre[class="highlight"],.listingblock pre[class^="highlight "],.listingblock pre.CodeRay,.listingblock pre.prettyprint{background:#f7f7f8}
.sidebarblock .literalblock pre,.sidebarblock .listingblock pre:not(.highlight),.sidebarblock .listingblock pre[class="highlight"],.sidebarblock .listingblock pre[class^="highlight "],.sidebarblock .listingblock pre.CodeRay,.sidebarblock .listingblock pre.prettyprint{background:#f2f1f1}
.literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class]{-webkit-border-radius:4px;border-radius:4px;word-wrap:break-word;padding:1em;font-size:.8125em}
.literalblock pre.nowrap,.literalblock pre[class].nowrap,.listingblock pre.nowrap,.listingblock pre[class].nowrap{overflow-x:auto;white-space:pre;word-wrap:normal}
@media only screen and (min-width:768px){.literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class]{font-size:.90625em}}@media only screen and (min-width:1280px){.literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class]{font-size:1em}}.literalblock.output pre{color:#f7f7f8;background-color:rgba(0,0,0,.9)}
.listingblock pre.highlightjs{padding:0}
.listingblock pre.highlightjs>code{padding:1em;-webkit-border-radius:4px;border-radius:4px}
.listingblock pre.prettyprint{border-width:0}
.listingblock>.content{position:relative}
.listingblock code[data-lang]:before{display:none;content:attr(data-lang);position:absolute;font-size:.75em;top:.425rem;right:.5rem;line-height:1;text-transform:uppercase;color:#999}
.listingblock:hover code[data-lang]:before{display:block}
.listingblock.terminal pre .command:before{content:attr(data-prompt);padding-right:.5em;color:#999}
.listingblock.terminal pre .command:not([data-prompt]):before{content:"$"}
table.pyhltable{border-collapse:separate;border:0;margin-bottom:0;background:none}
table.pyhltable td{vertical-align:top;padding-top:0;padding-bottom:0}
table.pyhltable td.code{padding-left:.75em;padding-right:0}
pre.pygments .lineno,table.pyhltable td:not(.code){color:#999;padding-left:0;padding-right:.5em;border-right:1px solid #ddddd8}
pre.pygments .lineno{display:inline-block;margin-right:.25em}
table.pyhltable .linenodiv{background:none!important;padding-right:0!important}
.quoteblock{margin:0 1em 1.25em 1.5em;display:table}
.quoteblock>.title{margin-left:-1.5em;margin-bottom:.75em}
.quoteblock blockquote,.quoteblock blockquote p{color:rgba(0,0,0,.85);font-size:1.15rem;line-height:1.75;word-spacing:.1em;letter-spacing:0;font-style:italic;text-align:justify}
.quoteblock blockquote{margin:0;padding:0;border:0}
.quoteblock blockquote:before{content:"\201c";float:left;font-size:2.75em;font-weight:bold;line-height:.6em;margin-left:-.6em;color:#7a2518;text-shadow:0 1px 2px rgba(0,0,0,.1)}
.quoteblock blockquote>.paragraph:last-child p{margin-bottom:0}
.quoteblock .attribution{margin-top:.5em;margin-right:.5ex;text-align:right}
.quoteblock .quoteblock{margin-left:0;margin-right:0;padding:.5em 0;border-left:3px solid rgba(0,0,0,.6)}
.quoteblock .quoteblock blockquote{padding:0 0 0 .75em}
.quoteblock .quoteblock blockquote:before{display:none}
.verseblock{margin:0 1em 1.25em 1em}
.verseblock pre{font-family:"Open Sans","DejaVu Sans",sans;font-size:1.15rem;color:rgba(0,0,0,.85);font-weight:300;text-rendering:optimizeLegibility}
.verseblock pre strong{font-weight:400}
.verseblock .attribution{margin-top:1.25rem;margin-left:.5ex}
.quoteblock .attribution,.verseblock .attribution{font-size:.9375em;line-height:1.45;font-style:italic}
.quoteblock .attribution br,.verseblock .attribution br{display:none}
.quoteblock .attribution cite,.verseblock .attribution cite{display:block;letter-spacing:-.05em;color:rgba(0,0,0,.6)}
.quoteblock.abstract{margin:0 0 1.25em 0;display:block}
.quoteblock.abstract blockquote,.quoteblock.abstract blockquote p{text-align:left;word-spacing:0}
.quoteblock.abstract blockquote:before,.quoteblock.abstract blockquote p:first-of-type:before{display:none}
table.tableblock{max-width:100%;border-collapse:separate}
table.tableblock td>.paragraph:last-child p>p:last-child,table.tableblock th>p:last-child,table.tableblock td>p:last-child{margin-bottom:0}
table.spread{width:100%}
table.tableblock,th.tableblock,td.tableblock{border:0 solid #dedede}
table.grid-all th.tableblock,table.grid-all td.tableblock{border-width:0 1px 1px 0}
table.grid-all tfoot>tr>th.tableblock,table.grid-all tfoot>tr>td.tableblock{border-width:1px 1px 0 0}
table.grid-cols th.tableblock,table.grid-cols td.tableblock{border-width:0 1px 0 0}
table.grid-all *>tr>.tableblock:last-child,table.grid-cols *>tr>.tableblock:last-child{border-right-width:0}
table.grid-rows th.tableblock,table.grid-rows td.tableblock{border-width:0 0 1px 0}
table.grid-all tbody>tr:last-child>th.tableblock,table.grid-all tbody>tr:last-child>td.tableblock,table.grid-all thead:last-child>tr>th.tableblock,table.grid-rows tbody>tr:last-child>th.tableblock,table.grid-rows tbody>tr:last-child>td.tableblock,table.grid-rows thead:last-child>tr>th.tableblock{border-bottom-width:0}
table.grid-rows tfoot>tr>th.tableblock,table.grid-rows tfoot>tr>td.tableblock{border-width:1px 0 0 0}
table.frame-all{border-width:1px}
table.frame-sides{border-width:0 1px}
table.frame-topbot{border-width:1px 0}
th.halign-left,td.halign-left{text-align:left}
th.halign-right,td.halign-right{text-align:right}
th.halign-center,td.halign-center{text-align:center}
th.valign-top,td.valign-top{vertical-align:top}
th.valign-bottom,td.valign-bottom{vertical-align:bottom}
th.valign-middle,td.valign-middle{vertical-align:middle}
table thead th,table tfoot th{font-weight:bold}
tbody tr th{display:table-cell;line-height:1.6;background:#f7f8f7}
tbody tr th,tbody tr th p,tfoot tr th,tfoot tr th p{color:rgba(0,0,0,.8);font-weight:bold}
p.tableblock>code:only-child{background:none;padding:0}
p.tableblock{font-size:1em}
td>div.verse{white-space:pre}
ol{margin-left:1.75em}
ul li ol{margin-left:1.5em}
dl dd{margin-left:1.125em}
dl dd:last-child,dl dd:last-child>:last-child{margin-bottom:0}
ol>li p,ul>li p,ul dd,ol dd,.olist .olist,.ulist .ulist,.ulist .olist,.olist .ulist{margin-bottom:.625em}
ul.unstyled,ol.unnumbered,ul.checklist,ul.none{list-style-type:none}
ul.unstyled,ol.unnumbered,ul.checklist{margin-left:.625em}
ul.checklist li>p:first-child>.fa-square-o:first-child,ul.checklist li>p:first-child>.fa-check-square-o:first-child{width:1em;font-size:.85em}
ul.checklist li>p:first-child>input[type="checkbox"]:first-child{width:1em;position:relative;top:1px}
ul.inline{margin:0 auto .625em auto;margin-left:-1.375em;margin-right:0;padding:0;list-style:none;overflow:hidden}
ul.inline>li{list-style:none;float:left;margin-left:1.375em;display:block}
ul.inline>li>*{display:block}
.unstyled dl dt{font-weight:400;font-style:normal}
ol.arabic{list-style-type:decimal}
ol.decimal{list-style-type:decimal-leading-zero}
ol.loweralpha{list-style-type:lower-alpha}
ol.upperalpha{list-style-type:upper-alpha}
ol.lowerroman{list-style-type:lower-roman}
ol.upperroman{list-style-type:upper-roman}
ol.lowergreek{list-style-type:lower-greek}
.hdlist>table,.colist>table{border:0;background:none}
.hdlist>table>tbody>tr,.colist>table>tbody>tr{background:none}
td.hdlist1{padding-right:.75em;font-weight:bold}
td.hdlist1,td.hdlist2{vertical-align:top}
.literalblock+.colist,.listingblock+.colist{margin-top:-.5em}
.colist>table tr>td:first-of-type{padding:0 .75em;line-height:1}
.colist>table tr>td:last-of-type{padding:.25em 0}
.thumb,.th{line-height:0;display:inline-block;border:solid 4px #fff;-webkit-box-shadow:0 0 0 1px #ddd;box-shadow:0 0 0 1px #ddd}
.imageblock.left,.imageblock[style*="float: left"]{margin:.25em .625em 1.25em 0}
.imageblock.right,.imageblock[style*="float: right"]{margin:.25em 0 1.25em .625em}
.imageblock>.title{margin-bottom:0}
.imageblock.thumb,.imageblock.th{border-width:6px}
.imageblock.thumb>.title,.imageblock.th>.title{padding:0 .125em}
.image.left,.image.right{margin-top:.25em;margin-bottom:.25em;display:inline-block;line-height:0}
.image.left{margin-right:.625em}
.image.right{margin-left:.625em}
a.image{text-decoration:none}
span.footnote,span.footnoteref{vertical-align:super;font-size:.875em}
span.footnote a,span.footnoteref a{text-decoration:none}
span.footnote a:active,span.footnoteref a:active{text-decoration:underline}
#footnotes{padding-top:.75em;padding-bottom:.75em;margin-bottom:.625em}
#footnotes hr{width:20%;min-width:6.25em;margin:-.25em 0 .75em 0;border-width:1px 0 0 0}
#footnotes .footnote{padding:0 .375em;line-height:1.3;font-size:.875em;margin-left:1.2em;text-indent:-1.2em;margin-bottom:.2em}
#footnotes .footnote a:first-of-type{font-weight:bold;text-decoration:none}
#footnotes .footnote:last-of-type{margin-bottom:0}
#content #footnotes{margin-top:-.625em;margin-bottom:0;padding:.75em 0}
.gist .file-data>table{border:0;background:#fff;width:100%;margin-bottom:0}
.gist .file-data>table td.line-data{width:99%}
div.unbreakable{page-break-inside:avoid}
.big{font-size:larger}
.small{font-size:smaller}
.underline{text-decoration:underline}
.overline{text-decoration:overline}
.line-through{text-decoration:line-through}
.aqua{color:#00bfbf}
.aqua-background{background-color:#00fafa}
.black{color:#000}
.black-background{background-color:#000}
.blue{color:#0000bf}
.blue-background{background-color:#0000fa}
.fuchsia{color:#bf00bf}
.fuchsia-background{background-color:#fa00fa}
.gray{color:#606060}
.gray-background{background-color:#7d7d7d}
.green{color:#006000}
.green-background{background-color:#007d00}
.lime{color:#00bf00}
.lime-background{background-color:#00fa00}
.maroon{color:#600000}
.maroon-background{background-color:#7d0000}
.navy{color:#000060}
.navy-background{background-color:#00007d}
.olive{color:#606000}
.olive-background{background-color:#7d7d00}
.purple{color:#600060}
.purple-background{background-color:#7d007d}
.red{color:#bf0000}
.red-background{background-color:#fa0000}
.silver{color:#909090}
.silver-background{background-color:#bcbcbc}
.teal{color:#006060}
.teal-background{background-color:#007d7d}
.white{color:#bfbfbf}
.white-background{background-color:#fafafa}
.yellow{color:#bfbf00}
.yellow-background{background-color:#fafa00}
span.icon>.fa{cursor:default}
.admonitionblock td.icon [class^="fa icon-"]{font-size:2.5em;text-shadow:1px 1px 2px rgba(0,0,0,.5);cursor:default}
.admonitionblock td.icon .icon-note:before{content:"\f05a";color:#19407c}
.admonitionblock td.icon .icon-tip:before{content:"\f0eb";text-shadow:1px 1px 2px rgba(155,155,0,.8);color:#111}
.admonitionblock td.icon .icon-warning:before{content:"\f071";color:#bf6900}
.admonitionblock td.icon .icon-caution:before{content:"\f06d";color:#bf3400}
.admonitionblock td.icon .icon-important:before{content:"\f06a";color:#bf0000}
.conum[data-value]{display:inline-block;color:#fff!important;background-color:rgba(0,0,0,.8);-webkit-border-radius:100px;border-radius:100px;text-align:center;font-size:.75em;width:1.67em;height:1.67em;line-height:1.67em;font-family:"Open Sans","DejaVu Sans",sans-serif;font-style:normal;font-weight:bold}
.conum[data-value] *{color:#fff!important}
.conum[data-value]+b{display:none}
.conum[data-value]:after{content:attr(data-value)}
pre .conum[data-value]{position:relative;top:-.125em}
b.conum *{color:inherit!important}
.conum:not([data-value]):empty{display:none}
h1,h2{letter-spacing:-.01em}
dt,th.tableblock,td.content{text-rendering:optimizeLegibility}
p,td.content{letter-spacing:-.01em}
p strong,td.content strong{letter-spacing:-.005em}
p,blockquote,dt,td.content{font-size:1.0625rem}
p{margin-bottom:1.25rem}
.sidebarblock p,.sidebarblock dt,.sidebarblock td.content,p.tableblock{font-size:1em}
.exampleblock>.content{background-color:#fffef7;border-color:#e0e0dc;-webkit-box-shadow:0 1px 4px #e0e0dc;box-shadow:0 1px 4px #e0e0dc}
.print-only{display:none!important}
@media print{@page{margin:1.25cm .75cm}
*{-webkit-box-shadow:none!important;box-shadow:none!important;text-shadow:none!important}
a{color:inherit!important;text-decoration:underline!important}
a.bare,a[href^="#"],a[href^="mailto:"]{text-decoration:none!important}
a[href^="http:"]:not(.bare):after,a[href^="https:"]:not(.bare):after{content:"(" attr(href) ")";display:inline-block;font-size:.875em;padding-left:.25em}
abbr[title]:after{content:" (" attr(title) ")"}
pre,blockquote,tr,img{page-break-inside:avoid}
thead{display:table-header-group}
img{max-width:100%!important}
p,blockquote,dt,td.content{font-size:1em;orphans:3;widows:3}
h2,h3,#toctitle,.sidebarblock>.content>.title{page-break-after:avoid}
#toc,.sidebarblock,.exampleblock>.content{background:none!important}
#toc{border-bottom:1px solid #ddddd8!important;padding-bottom:0!important}
.sect1{padding-bottom:0!important}
.sect1+.sect1{border:0!important}
#header>h1:first-child{margin-top:1.25rem}
body.book #header{text-align:center}
body.book #header>h1:first-child{border:0!important;margin:2.5em 0 1em 0}
body.book #header .details{border:0!important;display:block;padding:0!important}
body.book #header .details span:first-child{margin-left:0!important}
body.book #header .details br{display:block}
body.book #header .details br+span:before{content:none!important}
body.book #toc{border:0!important;text-align:left!important;padding:0!important;margin:0!important}
body.book #toc,body.book #preamble,body.book h1.sect0,body.book .sect1>h2{page-break-before:always}
.listingblock code[data-lang]:before{display:block}
#footer{background:none!important;padding:0 .9375em}
#footer-text{color:rgba(0,0,0,.6)!important;font-size:.9em}
.hide-on-print{display:none!important}
.print-only{display:block!important}
.hide-for-print{display:none!important}
.show-for-print{display:inherit!important}}
</style>
<style>
/* Stylesheet for CodeRay to match GitHub theme | MIT License | http://foundation.zurb.com */
/*pre.CodeRay {background-color:#f7f7f8;}*/
.CodeRay .line-numbers{border-right:1px solid #d8d8d8;padding:0 0.5em 0 .25em}
.CodeRay span.line-numbers{display:inline-block;margin-right:.5em;color:rgba(0,0,0,.3)}
.CodeRay .line-numbers strong{font-weight: normal}
table.CodeRay{border-collapse:separate;border-spacing:0;margin-bottom:0;border:0;background:none}
table.CodeRay td{vertical-align: top}
table.CodeRay td.line-numbers{text-align:right}
table.CodeRay td.line-numbers>pre{padding:0;color:rgba(0,0,0,.3)}
table.CodeRay td.code{padding:0 0 0 .5em}
table.CodeRay td.code>pre{padding:0}
.CodeRay .debug{color:#fff !important;background:#000080 !important}
.CodeRay .annotation{color:#007}
.CodeRay .attribute-name{color:#000080}
.CodeRay .attribute-value{color:#700}
.CodeRay .binary{color:#509}
.CodeRay .comment{color:#998;font-style:italic}
.CodeRay .char{color:#04d}
.CodeRay .char .content{color:#04d}
.CodeRay .char .delimiter{color:#039}
.CodeRay .class{color:#458;font-weight:bold}
.CodeRay .complex{color:#a08}
.CodeRay .constant,.CodeRay .predefined-constant{color:#008080}
.CodeRay .color{color:#099}
.CodeRay .class-variable{color:#369}
.CodeRay .decorator{color:#b0b}
.CodeRay .definition{color:#099}
.CodeRay .delimiter{color:#000}
.CodeRay .doc{color:#970}
.CodeRay .doctype{color:#34b}
.CodeRay .doc-string{color:#d42}
.CodeRay .escape{color:#666}
.CodeRay .entity{color:#800}
.CodeRay .error{color:#808}
.CodeRay .exception{color:inherit}
.CodeRay .filename{color:#099}
.CodeRay .function{color:#900;font-weight:bold}
.CodeRay .global-variable{color:#008080}
.CodeRay .hex{color:#058}
.CodeRay .integer,.CodeRay .float{color:#099}
.CodeRay .include{color:#555}
.CodeRay .inline{color:#00}
.CodeRay .inline .inline{background:#ccc}
.CodeRay .inline .inline .inline{background:#bbb}
.CodeRay .inline .inline-delimiter{color:#d14}
.CodeRay .inline-delimiter{color:#d14}
.CodeRay .important{color:#555;font-weight:bold}
.CodeRay .interpreted{color:#b2b}
.CodeRay .instance-variable{color:#008080}
.CodeRay .label{color:#970}
.CodeRay .local-variable{color:#963}
.CodeRay .octal{color:#40e}
.CodeRay .predefined{color:#369}
.CodeRay .preprocessor{color:#579}
.CodeRay .pseudo-class{color:#555}
.CodeRay .directive{font-weight:bold}
.CodeRay .type{font-weight:bold}
.CodeRay .predefined-type{color:inherit}
.CodeRay .reserved,.CodeRay .keyword {color:#000;font-weight:bold}
.CodeRay .key{color:#808}
.CodeRay .key .delimiter{color:#606}
.CodeRay .key .char{color:#80f}
.CodeRay .value{color:#088}
.CodeRay .regexp .delimiter{color:#808}
.CodeRay .regexp .content{color:#808}
.CodeRay .regexp .modifier{color:#808}
.CodeRay .regexp .char{color:#d14}
.CodeRay .regexp .function{color:#404;font-weight:bold}
.CodeRay .string{color:#d20}
.CodeRay .string .string .string{background:#ffd0d0}
.CodeRay .string .content{color:#d14}
.CodeRay .string .char{color:#d14}
.CodeRay .string .delimiter{color:#d14}
.CodeRay .shell{color:#d14}
.CodeRay .shell .delimiter{color:#d14}
.CodeRay .symbol{color:#990073}
.CodeRay .symbol .content{color:#a60}
.CodeRay .symbol .delimiter{color:#630}
.CodeRay .tag{color:#008080}
.CodeRay .tag-special{color:#d70}
.CodeRay .variable{color:#036}
.CodeRay .insert{background:#afa}
.CodeRay .delete{background:#faa}
.CodeRay .change{color:#aaf;background:#007}
.CodeRay .head{color:#f8f;background:#505}
.CodeRay .insert .insert{color:#080}
.CodeRay .delete .delete{color:#800}
.CodeRay .change .change{color:#66f}
.CodeRay .head .head{color:#f4f}
</style>
</head>
<body class="book">
<div id="header">
<h1>Working with types</h1>
</div>
<div id="content">
<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>Numbers are an important part of programming. Ultimately, computers <em>only</em> deal with numbers. As humans, though, we prefer some higher level types such as strings. In this chapter, I’ll show you how to use and interact with strings, collections, and maps. I’ll also introduce some other concepts such as fields and properties.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_the_joy_of_strings">The joy of strings</h2>
<div class="sectionbody">
<div class="paragraph">
<p>History has been recorded in the form of text for thousands of years - in stone, on paper, and now electronically. In that time, words have lost none of their power or usefulness. That’s why a basic type representing text is such a fundamental part of any programming language. And of course that type should be able to handle any language.</p>
</div>
<div class="paragraph">
<p>Groovy uses Java’s <a href="https://docs.oracle.com/javase/8/docs/api/?java/lang/String.html"><code>java.lang.String</code></a> class which is able to represent text in any written language supported by Unicode, or more specifically the 16-bit Unicode Transformation Format (UTF-16). If you’re interested, you can find a full list of supported scripts/alphabets <a href="http://www.unicode.org/standard/supported.html">on the Unicode website</a>. I’ll be using the latin alphabet almost exclusively in this book, but you can try this short script in the Groovy console to confirm support for other languages:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code>println "I live in London"
println "我住在北京"
println "ฉันอาศัยอยู่ในกรุงเทพฯ"
println "Ζω στην Αθήνα"</code></pre>
</div>
</div>
<div class="paragraph">
<p>The above consists of English, Chinese (Simplified), Thai, and Greek (using Google Translate of course - I only wish I could write in so many diverse languages!). Just bear in mind that you need a text editor or IDE that supports UTF-8 if you want to use non-Latin characters in Groovy source code. This is because the Groovy compiler assumes UTF-8 by default.</p>
</div>
<div class="paragraph">
<p>It’s quite possible to write a book about character encodings and internationalization, but it’s out of scope for a Groovy language introduction. So from here on in, I’ll be sticking to examples based on English. That will certainly make life easy for the next example which will involve some text analysis.</p>
</div>
<div class="sect2">
<h3 id="_strings_are_sequences">Strings are sequences</h3>
<div class="paragraph">
<p>What is text? It’s inherently a sequence of characters, which means you can evaluate its length, reorder it, extract substrings and count the number of vowels or consonants in it. It also means you can iterate over the characters.</p>
</div>
<div class="paragraph">
<p>Let’s see how this works in Groovy. We start with a piece of text (a string), evaluate the properties we just described (length, etc.) and then print that information out:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code>def text = "Jack Rabbit Slims Twist Contest"
println "Text length: " + text.size() <b class="conum">(1)</b>
println "First character: " + text[0] <b class="conum">(2)</b>
println "Last character: " + text[-1]
final vowels = "aeiou" <b class="conum">(3)</b>
def vowelCount = 0
for (ch in text) { <b class="conum">(4)</b>
if (vowels.contains(ch.toLowerCase())) {
vowelCount++
}
}
println "Number of vowels: " + vowelCount</code></pre>
</div>
</div>
<div class="colist arabic">
<ol>
<li>
<p>Concatenate strings with the <code>+</code> operator</p>
</li>
<li>
<p>Access individual characters</p>
</li>
<li>
<p>Declare a constant using <code>final</code></p>
</li>
<li>
<p>Iterate over the characters of the string</p>
</li>
</ol>
</div>
<div class="paragraph">
<p>This example introduces several properties of strings:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Concatenation with <code>+</code></p>
<div class="paragraph">
<p>You can build up strings this way with any values, including numbers, lists and so on. The only requirement is that the concatenation starts with a string.</p>
</div>
</li>
<li>
<p>Text length with <code>size()</code></p>
<div class="paragraph">
<p>Java is annoying because you need to use different fields or methods to get the lengths of arrays, lists, and strings. In Groovy, you can just use the <code>size()</code> method for all types of sequence. You can find this method documented in the <a href="http://docs.groovy-lang.org/docs/next/html/groovy-jdk/?java/lang/String.html">Groovy JDK entry for String</a>.</p>
</div>
</li>
<li>
<p>Array indexing to extract characters</p>
<div class="paragraph">
<p>You can use the syntax of <code>[index]</code> on any type of sequence to pick out a particular element. The first element of a sequence is at index 0. If you want to index from the end of a sequence, use a negative number. So -1 represents the last element, -2 the second to last, and so on.</p>
</div>
<div class="paragraph">
<p>One thing to note is that the array index operator returns a single character string in this case, rather than a <code>java.lang.Character</code>. You can verify this by adding a line <code>println text[0].getClass()</code> to the script. I’ll discuss the <code>Character</code> type shortly as Groovy is noticeably different from Java on this score.</p>
</div>
</li>
<li>
<p>Looping with <code>for</code></p>
<div class="paragraph">
<p>The standard Groovy <code>for</code> loop works on any type of sequence, just like the array index operator. And similarly, each iteration gives you a single character string to work with instead of a <code>Character</code>. If you want to be more explicit you can include the type:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code>for (String ch in text) {
...
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>This does of course raise the question of when to explicitly specify the type of the iteration variable. It’s a question that always crops up with Groovy because of its optional typing, hence why I discuss it more thoroughly in chapter [TODO] once you know most of the basics. In this particular case, it’s easy to infer the type of <code>ch</code> and so the type isn’t necessary. But some people may be more comfortable with it being explicit, and that’s fine too.</p>
</div>
</li>
</ul>
</div>
<div class="paragraph">
<p>I just want to finish off this section by identifying the source of the string methods used in the example. I’ve already mentioned that <code>size()</code> is provided by the Groovy JDK, but so is <code>toLowerCase()</code>, which returns a new string with all letters lower-cased. The <code>contains()</code> method is different because it is provided by the JDK itself.</p>
</div>
<div class="paragraph">
<p>This sort of thing can be frustrating: how are you supposed to know where to find these methods in the API docs? The best advice is to stay calm and just look at both the Java API and Groovy JDK docs when searching for a method. Alternatively, use an IDE that will give you auto completion: Eclipse, IntelliJ and NetBeans all have great Groovy integration. As you become more familiar with the APIs, you’ll learn where the various methods come from.</p>
</div>
<div class="paragraph">
<p>Before moving on, there is one improvement I’d like to make to the script. I like things to be formatted so that they are more readable. The summary of the text analysis just doesn’t cut it at the moment as the values are misaligned. We can easily remedy that in Groovy using one of its methods related to padding. In this case, we want to pad the labels so that the values all appear left-aligned:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code>def text = "Jack Rabbit Slims Twist Contest"
final padding = 20
println "Text length: ".padRight(padding) + text.size()
println "First character: ".padRight(padding) + text[0]
println "Last character: ".padRight(padding) + text[-1]
...</code></pre>
</div>
</div>
<div class="paragraph">
<p>You could also try right-aligning the labels by using the <code>padLeft()</code> method instead.</p>
</div>
</div>
<div class="sect2">
<h3 id="_string_expansion">String expansion</h3>
<div class="paragraph">
<p>As you’ve just seen, string concatenation works just fine. That said, it does add noise to your code, particularly when there is more text than expressions. An alternative approach in Groovy is to use string expansion, by embedding expressions inside <code>${}</code> place holders:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code>...
println "I found ${vowelCount} vowels in the text"</code></pre>
</div>
</div>
<div class="paragraph">
<p>I consider this to be more readable than</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code>...
println "I found " + vowelCount + " vowels in the text"</code></pre>
</div>
</div>
<div class="paragraph">
<p>It’s also easier to keep track of the spaces you need. Did I remember to include the space after 'found' and the one before 'vowels'? It’s not so clear with string concatenation.</p>
</div>
<div class="paragraph">
<p>You will often see an alternative form (without the curly braces) for embedding variables:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code>println "I found $vowelCount vowels in the text"</code></pre>
</div>
</div>
<div class="paragraph">
<p>It’s a little less noisy, but the expression doesn’t stand out so well. I tend to recommend to newcomers that they only use the former syntax (with curly braces) for consistency and to avoid some confusing edge cases with the latter approach. Ultimately it’s a style thing and up to you or your team.</p>
</div>
<div class="paragraph">
<p>So what happens when you want to include an actual dollar symbol in the string? Try this code snippet in the Groovy console:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code>println "I sent them a $1000 check by post"</code></pre>
</div>
</div>
<div class="paragraph">
<p>I see an error message:</p>
</div>
<div class="literalblock">
<div class="content">
<pre>illegal string body character after dollar sign;
solution: either escape a literal dollar sign "\$5" or
bracket the value expression "${5}" at line: 1, column: 1</pre>
</div>
</div>
<div class="paragraph">
<p>It’s pretty clear that Groovy’s not happy about that <code>$</code> in the string. One solution is to escape it using a backslash:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code>println "I sent them a \$1000 check by post"</code></pre>
</div>
</div>
<div class="paragraph">
<p>It works, but isn’t pretty. Also imagine if you have a much larger string with lots of <code>$</code> symbols. What are the chances that you’re going to remember to escape all of them? In such cases, I prefer an alternative string literal using single quotes:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code>println 'I sent them a $1000 check by post'</code></pre>
</div>
</div>
<div class="paragraph">
<p>The only difference between the single-quote and double-quote versions is that the latter supports embedded expressions. It’s also important to understand that there is no memory or performance difference between the two. A double-quote string without any embedded expressions is still a plain <code>java.lang.String</code>. The decision to use one over the other then becomes one of personal preference. I prefer to use double quotes in most cases because I can easily insert an embedded expression at a later date without also changing the quotes. Others like the extra information tied to using single quotes, i.e. it is just a plain string.</p>
</div>
</div>
<div class="sect2">
<h3 id="_multi_line_strings">Multi-line strings</h3>
<div class="paragraph">
<p>This is the kind of thing that people have long discussions and arguments over, so let’s move swiftly on before we end up in the same boat. Imagine you want to include a block of text in your code - perhaps it’s an email template or long, formatted message you want to display to users. The easiest way to do this in Groovy is with a multi-line string literal:</p>
</div>
<div class="listingblock">
<div class="title">Listing 2.1</div>
<div class="content">
<pre class="CodeRay highlight"><code>def sayHello(name) {
println """Dear ${name},
Thank you for signing up to our product. We hope you enjoy!
Kind regards,
Customer Services
"""
}
sayHello("Peter")</code></pre>
</div>
</div>
<div class="paragraph">
<p>So simply by using three quotes at the beginning and end, you’re allowed to put line breaks in the text. This is much nicer than using the <code>\n</code> new line character. Also notice how the above example includes an embedded expression: that’s because it uses double quotes. You can also use three single quotes (<code>'''</code>) instead, in which case the expression doesn’t get evaluated.</p>
</div>
<div class="paragraph">
<p>So far, so simple. But what if you don’t like aligning the text in the first column of the source file? Perhaps you’d prefer to indent it like so:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code>def sayHello(name) {
println """Dear ${name},
Thank you for signing up to our product. We hope you enjoy!
Kind regards,
Customer Services
"""
}
sayHello("Peter")</code></pre>
</div>
</div>
<div class="paragraph">
<p>Unfortunately, the spaces at the beginning of each line will end up in the output because they are part of the text. All is not lost, though! The Groovy JDK provides some extra methods that are ideal for such scenarios: <code>stripIndent()</code> and <code>stripMargin()</code>.</p>
</div>
<div class="paragraph">
<p>The first of these remove any leading whitespace that is common to all lines. The second, <code>stripMargin()</code>, removes all leading characters up to a specific character (<code>|</code> by default). We’re going to use <code>stripIndent()</code> here, but there is one thing we need to be wary of: every line has to have the leading whitespace for it to be removed. And the code as it stands doesn’t have leading whitespace for the first line!</p>
</div>
<div class="paragraph">
<p>To solve that, we’re going to use a <em>line continuation</em>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code>def sayHello(name) {
println """\ <b class="conum">(1)</b>
Dear ${name}, <b class="conum">(2)</b>
Thank you for signing up to our product. We hope you enjoy!
Kind regards,
Customer Services
""".stripIndent() <b class="conum">(3)</b>
}
sayHello("Peter")</code></pre>
</div>
</div>
<div class="colist arabic">
<ol>
<li>
<p><code>\</code> followed by a new line cancels the line break</p>
</li>
<li>
<p>The first line of text now has leading whitespace</p>
</li>
<li>
<p>Removes the leading whitespace from each line</p>
</li>
</ol>
</div>
<div class="paragraph">
<p>I almost always use a line continuation for the first line of multi-line strings, just to ensure nice alignment. The main issue that typically arises from this technique is the presence of spaces or tabs after the backslash. For line continuations to work, the backslash <em>must</em> be the last character of that source code line.</p>
</div>
</div>
<div class="sect2">
<h3 id="_characters_and_type_coercion">Characters and type coercion</h3>
<div class="paragraph">
<p>As you’ve seen, Groovy treats strings as if they are sequences of single-character strings. This seems a little strange as the Java class library does have a specific type representing a single character: <a href="https://docs.oracle.com/javase/8/docs/api/?java/lang/Character.html"><code>java.lang.Character</code></a>. Does this mean that you shouldn’t use <code>Character</code> from Groovy?</p>
</div>
<div class="paragraph">
<p>The simple fact is that it would be hard not to use <code>Character</code> when so many Java APIs that you might want to use rely on them. For example, if you want to check whether a character is an alphabetic letter, you can use the static <code>Character.isLetter()</code> method. It takes a <code>Character</code> as its argument. To understand the problem better, consider this example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code>def text = "Jack Rabbit Slims Twist Contest"
if (Character.isUpperCase(text[0])) {
println "The text starts with a capital letter!"
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Running this results in another one of those pesky missing-something exceptions:</p>
</div>
<div class="literalblock">
<div class="content">
<pre>groovy.lang.MissingMethodException: No signature of method: static java.lang.Character.isUpperCase() is applicable for argument types: (java.lang.String) values: [J]
Possible solutions: isUpperCase(), isUpperCase(char), isUpperCase(int), toUpperCase(), toUpperCase(char), toUpperCase(int)
at ConsoleScript27.run(ConsoleScript27:2)</pre>
</div>
</div>
<div class="paragraph">
<p>As the exception says, there is no <code>isUpperCase()</code> method that takes a string. So how do you get a <code>Character</code> in Groovy? The solution lies in a multi-purpose conversion mechanism.</p>
</div>
<div class="paragraph">
<p>Groovy provides two conversion options, one implicit and the other explicit. The implicit version consists of assigning a value of one type to a local variable declared as another type. Applying this to the previous example, we get</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code>def text = "Jack Rabbit Slims Twist Contest"
Character ch = text[0] <b class="conum">(1)</b>
if (Character.isUpperCase(ch)) {
println "The text starts with a capital letter!"
}</code></pre>
</div>
</div>
<div class="colist arabic">
<ol>
<li>
<p>Explicitly declare the local variable as the required type</p>
</li>
</ol>
</div>
<div class="paragraph">
<p>This approach also works for variables declared in <code>for</code> loops:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code>def text = "Jack Rabbit Slims Twist Contest"
def upperCount = 0
for (Character ch in text) { <b class="conum">(1)</b>
if (Character.isUpperCase(ch)) {
upperCount++
}
}
println "There are ${upperCount} upper case letters"</code></pre>
</div>
</div>
<div class="colist arabic">
<ol>
<li>
<p>Explicitly declare the type of the loop variable</p>
</li>
</ol>
</div>
<div class="paragraph">
<p>The second, explicit, approach involves a new operator: <code>as</code>. This is particularly useful when introducing a new variable just adds noise to the code. The previous example where we introduced a new local variable would be better coded as</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code>def text = "Jack Rabbit Slims Twist Contest"
if (Character.isUpperCase(text[0] as Character)) { <b class="conum">(1)</b>
println "The text starts with a capital letter!"
}</code></pre>
</div>
</div>
<div class="colist arabic">
<ol>
<li>
<p>Use <code>as</code> to coerce a value to a different type</p>
</li>
</ol>
</div>
<div class="paragraph">
<p>Whichever approach you use, just be aware that it doesn’t just magically convert all types to all other types. The built-in support has limited knowledge and is mostly used for:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Converting a single-character string to a <code>Character</code></p>
</li>
<li>
<p>Upgrading numbers, for example from <code>Integer</code> to <code>Long</code></p>
</li>
<li>
<p>Converting a list to an array (I’ll talk about this a little later)</p>
</li>
<li>
<p>Creating a set from a list</p>
</li>
<li>
<p>Converting pretty much anything to a <code>String</code>, since every type has a <code>toString()</code> method</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>You can’t, for example, assign a string with more than one character in it to a <code>Character</code> variable. You’ll get a <code>GroovyCastException</code>. That’s good because automatic coercions are very useful but can cause productivity-sapping surprises when too prevalent. And remember that coercion does not happen automatically for method arguments, even if they are explicitly typed.</p>
</div>
<div class="sidebarblock">
<div class="content">
<div class="title">Object vs primitive types</div>
<div class="paragraph">
<p>Groovy inherits Java’s type system, which means that you get both primitive and object types. For example, <code>char</code> and <code>Character</code>. These two types are interchangeable in Groovy as you can call methods on primitive types. The main difference is that object types can have a <code>null</code> value.</p>
</div>
<div class="paragraph">
<p>I tend to prefer the primitive types because they are shorter and I rarely want to allow <code>null</code> values for them. The available primitive types (and corresponding object types) are:</p>
</div>
<table class="tableblock frame-all grid-all spread">
<colgroup>
<col style="width: 50%;">
<col style="width: 50%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Primitive type</th>
<th class="tableblock halign-left valign-top">Object type</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>char</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>Character</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>byte</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>Byte</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>short</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>Short</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>int</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>Integer</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>long</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>Long</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>float</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>Float</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>double</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>Double</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>boolean</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>Boolean</code></p></td>
</tr>
</tbody>
</table>
<div class="paragraph">
<p>From this point on, I’ll use primitive types unless an object type is required for some reason.</p>
</div>
</div>
</div>
<div class="paragraph">
<p>Strings aren’t the only form of sequences. What if you want a shopping list or a simple sequence of numbers? A list is a more generic form of sequence available in Groovy and we look at that next alongside other types of collection.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_collections_ranges_and_maps">Collections, ranges and maps</h2>
<div class="sectionbody">
<div class="paragraph">
<p>When programming, we often need to deal with collections of objects, not just single instances. That’s why most languages have built-in support for lists (an ordered collection or sequence) and other types of collection. As with strings, it’s the Java class library that provides these types in Groovy. That doesn’t mean that you get the same experience as if you’re developing in Java. In fact, Groovy brings a greater level of consistency and expressiveness.</p>
</div>
<div class="paragraph">
<p>We’ll start with ordered collections, which are represented by the <a href="https://docs.oracle.com/javase/8/docs/api/?java/util/List.html"><code>java.util.List</code></a> interface. In the following example, I create a list of words (strings) and then proceed to iterate over them to calculate the shortest, longest and average word lengths. Before you critize the implementation (there are better ways to do this), remember that I’m trying to introduce new concepts and APIs gradually!</p>
</div>
<div id="wordStats" class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code>final words = ["orange", "sit", "test", "flabbergasted", "honorific"] <b class="conum">(1)</b>
def minWordLength = Integer.MAX_VALUE <b class="conum">(2)</b>