-
Notifications
You must be signed in to change notification settings - Fork 2
/
The-Go-Programming-Language_es.morg
22271 lines (18368 loc) · 927 KB
/
The-Go-Programming-Language_es.morg
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
..title > El lenguaje de programacion Go
..author > Alan A. A. Donovan
..author > Brian W. Kernighan
..date > 29/09/2015
..id > isbn-13 978-0-13-419044-0
..id > isbn-10 0-13-419044-0
..style > worg-data/worg.css
..options > fancyCode toc
@ revision 3b600c, date 29 Sep 2015
..center >
Para Leila y Meg
< center..
* Prefacio
..quote >
@"(Go es un lenguaje de programacion de codigo abierto, que facilita la
creacion de software simple, confiable y eficiente.)
--(Desde el sitio web de Go en @l(https://golang.org/<>golang.org))
< quote..
Go fue concebido en septiembre de 2007 por Robert Griesemer, Rob Pike y Ken
Thompson, todos de Google, y fue anunciado en noviembre de 2009. La meta del
lenguaje y sus herramientas acompañantes es ser expresivos, eficientes en la
compilacion y ejecucion, y eficaz en la escritura de programas fiables y
robustos.
Go tiene una similitud superficial con C y, como C, es una herramienta para
programadores profesionales, logrando el maximo efecto con un minimo de
medios. Pero es mucho mas que una version actualizada de C. Toma prestadas y
adapta buenas ideas de muchos otros lenguajes, evitando caracteristicas que
han llevado a la complejidad y a un codigo poco confiable. Sus comodidades
para la concurrencia son nuevas y eficientes, y su enfoque hacia la
abstraccion de datos y la programacion orientada a objetos es inusualmente
flexible. Tambien cuenta con gestion automatica de memoria o @e(recoleccion de
basura).
Go es especialmente adecuado para la construccion de infraestructura como
servidores en red, y herramientas y sistemas para programadores, pero es
realmente un lenguaje de uso general y se utiliza en dominios tan diversos
como graficos, aplicaciones moviles y aprendizaje automatico. Se ha vuelto
popular como un reemplazo para los lenguajes de scripting no tipados porque
equilibra la expresividad con la seguridad: Los programas Go suelen funcionar
mas rapido que los programas escritos en lenguajes dinamicos y sufren muchos
menos accidentes debido a errores de tipado.
Go es un proyecto de codigo abierto, por lo que el codigo fuente de su
compilador, librerias y herramientas esta disponible gratuitamente para
cualquiera. Las contribuciones al proyecto provienen de una activa comunidad
mundial. Go se ejecuta en sistemas tipo Unix–GNU/Linux, FreeBSD, OpenBSD,
Mac OS X–y en Plan 9 y Microsoft Windows. Los programas escritos en uno de
estos entornos generalmente funcionan sin modificacion en los otros.
Este libro esta diseñado para ayudarle a comenzar a usar Go efectivamente, de
inmediato y utilizarlo bien, aprovechando al maximo las caracteristicas
lingüisticas de Go y las librerias estandar para escribir programas claros,
idiomaticos y eficientes.
** Los Origenes de Go
Como las especies biologicas, los lenguajes exitosos engendran hijos que
incorporan las ventajas de sus antepasados; el entrecruzamiento a veces
conduce a fortalezas sorprendentes; y, muy ocasionalmente, surge un nuevo
rasgo radical sin precedentes. Podemos aprender mucho sobre por que un
lenguaje es como es y a que entorno se ha adaptado para ver estas
influencias.
La siguiente figura muestra las influencias mas importantes de los lenguajes
de programacion anteriores en el diseño de Go.
..img > img/go-influences.jpg
En ocaciones Go se describe como un @"(lenguaje de tipo C), o como @"(C para
el siglo 21). De C, Go heredo su sintaxis de expresiones, instrucciones de
flujo de control, tipos de datos basicos, paso de parametros por valor, punteros
y, sobre todo, el enfasis de C en programas que compilan codigo maquina
eficiente y cooperan naturalmente con las abstracciones de los sistemas
operativos actuales.
Pero hay otros antepasados en el arbol genealogico de Go. Una importante
corriente de influencia proviene de los lenguajes de Niklaus Wirth, comenzando
con Pascal. Modula-2 inspiro el concepto de paquete. Oberon elimino la
distincion entre los archivos de interfaz del modulo y los archivos de
implementacion del modulo. Oberon-2 influyo en la sintaxis de importacion y
declaracion de paquetes, y proporciono la sintaxis para la declararcion de
metodos.
Otro linaje entre los antepasados de Go, y uno que hace a Go distinto entre
los lenguajes de programacion mas recientes, es una secuencia de lenguajes de
investigacion poco conocidos desarrollados en los Laboratorios Bell, todos
ellos inspiradas en el concepto de comunicacion de procesos secuenciales
(CSP) del seminal articulo de 1978 de Tony Hoare en los cimientos de la
concurrencia. En CSP, un programa es una composicion paralela de procesos que
no tienen estado compartido; los procesos se comunican y sincronizan
utilizando canales. Pero el CSP de Hoare era un lenguaje formal para
describir los conceptos fundamentales de la concurrencia, no un lenguaje de
programacion para escribir programas ejecutables.
Rob Pike y otros comenzaron a experimentar con implementaciones CSP como
lenguajes reales. El primero fue llamado Squeak @%"(Un Lenguaje para
comunicarce con ratones), que proporcionaron un lenguaje para el manejo de
eventos de raton y teclado, con canales estaticamente creados. Esto fue
seguido por Newsqueak, que ofrecia declaraciones y sintaxis de expresion como
C y la notacion de tipo Pascal. Se trataba de un lenguaje puramente funcional
con recoleccion de basura, dirigido nuevamente a administrar eventos de
teclado, raton y ventanas. Los canales se convirtieron en valores de primera
clase, creados dinamicamente y almacenados en variables.
El sistema operativo Plan 9 llevo adelante estas ideas en un lenguaje llamado
Alef. Alef trato de hacer de Newsqueak un lenguaje viable para la
programacion de sistemas, pero su omision de un recoleccion de basura hizo
que la concurrencia fuera demasiado dolorosa.
Otras construcciones en Go muestran la influencia de genes no ancestrales
aqui y alla; por ejemplo @c(iota) es tomado libremente de APL, y el ambito
lexico con funciones anidadas es de Scheme (y la mayoria de lenguajes desde
entonces). Aqui tambien encontramos mutaciones novedosas. Go innova
proporcionando slices (arreglos dinamicos) con acceso aleatorio eficiente,
pero tambien permite sofisticados arreglos compartidos que recuerdan a las
listas enlazadas. Y la declaracion @c(defer) es nueva con Go.
** El Proyecto Go
Todos los lenguajes de programacion reflejan la filosofia de programacion de
sus creadores, que a menudo incluye un componente significativo de reaccion a
las deficiencias percibidas de los lenguajes anteriores. El proyecto Go nacio de
la frustracion con varios sistemas de software de Google que sufrian una
explosion de complejidad. (Este problema no es exclusivo de Google.)
Como Rob Pike dijo, @"(la complejidad es multiplicativa): solucionar un
problema al hacer una parte del sistema mas compleja, lentamente pero con
seguridad añade complejidad a otras partes. Con la presion constante de
agregar caracteristicas y opciones y configuraciones, y de enviar codigo
rapidamente, es facil olvidar la sencillez, aunque a la larga la simplicidad
es la clave para un buen software.
La simplicidad requiere mas trabajo al comienzo de un proyecto para reducir
una idea a su esencia y mas disciplina durante la vida de un proyecto para
distinguir los buenos cambios, de los malos o perniciosos. Con un esfuerzo
suficiente, un buen cambio se puede acomodar sin comprometer lo que Fred
Brooks llamo la @"(integridad conceptual) del diseño, pero un mal cambio no
puede, y un cambio pernicioso negocia la sencillez por una conveniencia
superficial. Solo a traves de la simplicidad del diseño un sistema puede
permanecer estable, seguro y coherente a medida que crece.
El proyecto Go incluye el lenguaje mismo, sus herramientas y librerias
estandar, y por ultimo, pero no menos importante, una agenda cultural de
simplicidad radical. Como un lenguaje reciente de alto nivel, Go tiene el
beneficio de la retrospeccion, y lo basico esta bien hecho: tiene recoleccion
de basura, un sistema de paquetes, funciones de primera clase, alcance
lexico, una interfaz de llamadas al sistema y cadenas inmutables en las que
el texto esta generalmente codificado en UTF-8. Pero tiene comparativamente
pocas caracteristicas y es poco probable que agregue mas. Por ejemplo, no
tiene conversiones numericas implicitas, no hay constructores o destructores,
no hay sobrecarga de operadores, no hay valores de parametros
predeterminados, ni herencia, ni genericos, ni excepciones, ni macros, ni
anotaciones de funcion, ni almacenamiento local de hilos. El lenguaje es
maduro y estable y garantiza la compatibilidad con versiones anteriores: los
programas Go mas antiguos se pueden compilar y ejecutar con versiones mas
recientes de compiladores y librerias estandar.
Go tiene un sistema de tipado para evitar la mayoria de los errores por
descuido que afectan a los programadores en lenguajes dinamicos, pero tiene
un sistema de tipado mas simple que los lenguajes tipados comparables. Este
enfoque puede conducir en ocaciones a baches de programacion @"(sin tipado)
dentro de un marco mas amplio de tipos, y los programadores de Go no hacen lo
que los programadores de C++ o Haskell para expresar las propiedades de
seguridad como pruebas basadas en tipos. Pero en la practica, Go da a los
programadores gran parte de los beneficios de seguridad y rendimiento en
tiempo de ejecucion de un sistema de tipado relativamente fuerte sin la carga
de complejidad.
Go fomenta una conciencia del diseño de sistemas informaticos contemporaneos,
particularmente la importancia de la localidad. Sus tipos de datos
incorporados y la mayoria de las estructuras de datos de la libreria estan
diseñados para funcionar naturalmente sin inicializacion explicita o
constructores implicitos, por lo que relativamente pocas asignaciones de
memoria y escrituras de memoria estan ocultas en el codigo. Los tipos
agregados de Go (estructuras y matrices) mantienen sus elementos
directamente, requiriendo menos almacenamiento y menos asignaciones e
indireccion de punteros, que los lenguajes que utilizan campos indirectos. Y
como la computadora moderna es una maquina paralela, Go tiene caracteristicas
de concurrencia basadas en CSP, como se menciono anteriormente. Las pilas de
tamaño variable de los hilos ligeros de Go o @e(gorutinas) son inicialmente
lo suficientemente pequeñas como para que crear una gorutina sea barato y
crear un millon sea practico.
La libreria estandar de Go, a menudo descrita como con @"(baterias
incluidas,) proporciona bloques de construccion limpios y APIs de E/S,
procesamiento de texto, graficos, criptografia, redes y aplicaciones
distribuidas, con soporte para muchos formatos de archivos y protocolos
estandar. Las librerias y las herramientas hacen uso extensivo de la
convencion para reducir la necesidad de configuracion y explicaciones,
simplificando asi la logica del programa y haciendo que diversos programas Go
sean mas similares entre si y, por lo tanto, mas faciles de aprender. Los
proyectos creados con la herramienta @$(go) solo utilizan nombres de archivos
e identificadores y un comentario especial ocasional para determinar todas
las librerias, ejecutables, pruebas, referencias, ejemplos, variantes
especificas de la plataforma y documentacion para un proyecto; el codigo
fuente de Go contiene en si la especificacion de compilacion.
** Organizacion del Libro
Asumimos que usted ha programado en uno o mas lenguajes, ya sea compilados como C,
C++ y Java, o interpretados como Python, Ruby y JavaScript, por lo que no
solemos explicar todo como si fuera un completo principiante. La sintaxis
superficial sera familiar, al igual que variables y constantes, expresiones,
flujo de control y funciones.
El Capitulo 1 es un tutorial sobre las construcciones basicas de Go,
introducido a traves de una docena de programas para tareas cotidianas como
leer y escribir archivos, formatear texto, crear imagenes y comunicarse con
clientes y servidores de Internet.
El Capitulo 2 describe los elementos estructurales de un programa
Go–declaraciones, variables, nuevos tipos, paquetes y archivos, y alcance. El
Capitulo 3 analiza numeros, booleanos, cadenas y constantes, y explica como
procesar Unicode. El Capitulo 4 describe los tipos compuestos, es decir, los
tipos construidos a partir de los mas sencillos utilizando arreglos, mapas,
estructuras y slices, la aproximacion de Go para listas dinamicas. El
Capitulo 5 cubre las funciones y discute el manejo de errores,
@c(panic) y @c(recover), y la sentencia @c(defer).
Los Capitulos 1 a 5 son por lo tanto, lo basico, las cosas que forman
parte de cualquier lenguaje imperativo popular. La sintaxis y el estilo de Go
a veces difieren de otros lenguajes, pero la mayoria de los programadores los
captan rapidamente. Los capitulos restantes se centran en temas en los que
el enfoque de Go es menos convencional: metodos, interfaces, concurrencia,
paquetes, pruebas y reflexion.
Go tiene un acercamiento inusual a la programacion orientada a objetos. No
hay jerarquias de clase, o de hecho ninguna clase; los comportamientos de
objetos complejos se crean a partir de los mas simples por composicion, no
por herencia. Los metodos pueden ser asociados con cualquier tipo definido
por el usuario, no solo las estructuras, y la relacion entre tipos concretos
y tipos abstractos (las @e(interfaces)) son implicitas, por lo que un tipo
concreto puede satisfacer una interfaz que el diseñador del tipo desconocia.
Los metodos estan cubiertos en el Capitulo 6, las interfaces en el Capitulo 7.
El Capitulo 8 presenta el enfoque de Go sobre la concurrencia, que se basa en la
idea de comunicar procesos secuenciales (CSP), incorporados por gorutinas y
canales. El Capitulo 9 explica los aspectos mas tradicionales de la
concurrencia basada en variables compartidas.
El Capitulo 10 describe los paquetes, el mecanismo para organizar las
librerias. Este capitulo tambien muestra como hacer un uso efectivo de la
herramienta @$(go), provista para la compilacion, pruebas, benchmarking,
formateo del programa, documentacion y muchas otras tareas, todo dentro de un
solo comando.
El Capitulo 11 trata de las pruebas, donde Go adopta un enfoque notablemente
ligero, evitando framewoks cargados de abstraccion en favor de librerias y
herramientas simples. Las librerias de pruebas proporcionan una base sobre
la que se pueden construir abstracciones mas complejas si es necesario.
El Capitulo 12 discute la reflexion, la capacidad de un programa para
examinar su propia representacion durante la ejecucion. La reflexion es una
herramienta poderosa, aunque debe ser usada con cuidado; este capitulo
explica como encontrar el equilibrio correcto, mostrando como se utiliza para
implementar algunas librerias importantes en Go. El Capitulo 13 explica los
detalles morbosos de programacion a bajo nivel que utiliza el paquete
@c(unsafe) para dar un paso alrededor del sistema de tipado de Go, y cuando
eso es apropiado.
Cada capitulo tiene una serie de ejercicios que puedes usar para probar tu
comprension de Go, y para explorar extensiones y alternativas a los ejemplos
del libro.
Todos menos los ejemplos de codigo, exepto los mas triviales estan
disponibles para su descarga desde un repositorio publico Git en
@l(http://www.gopl.io/<>gopl.io). Cada ejemplo se identifica por su ruta de
importacion de paquete y puede ser convenientemente localizado, construido e
instalado utilizando el comando @$(go get). Tendras que elegir un directorio
para que sea tu espacio de trabajo y establecer la variable de entorno
@c(GOPATH) apuntando a el. La herramienta @$(go) creara el directorio si es
necesario. Por iejemplo:
..srci > sh
> export GOPATH=$HOME/gobook # Elegir el directorio de trabajo
> go get gopl.io/ch1/helloworld # buscar, construir, instalar
> $GOPATH/bin/helloworld # ejecutar
Hello, 世界
< srci..
Para ejecutar los ejemplos, necesitara al menos la version 1.5 de Go.
..srci > sh
> go version
go version go1.5 linux/amd64
< srci..
Siga las instrucciones en @l(https://golang.org/doc/install) si en su equipo
la herramienta @$(go) esta ausente o es antigua.
** Donde Encontrar Mas Informacion
La mejor fuente para obtener mas informacion sobre Go es el sitio web
oficial, @l(https://golang.org), que proporciona acceso a la documentacion,
incluyendo la @e(Especificacion del Lenguaje de Programacion Go), los
paquetes estandar, y similares. Tambien hay tutoriales sobre como escribir Go
y como escribirlo bien, y una amplia variedad de recursos de texto y video en
linea que seran valiosos complementos para este libro. El Blog de Go se
encuentra en @l(https://blog.golang.org<>blog.golang.org) donde se publican
algunos de los mejores escritos de Go, con articulos sobre el estado del
lenguaje, los planes a futuro, los informes sobre conferencias y
explicaciones en profundidad de una amplia variedad de temas relacionados.
Uno de los aspectos mas utiles del acceso en linea a Go (y una limitacion
lamentable de un libro de papel) es la capacidad de ejecutar programas Go
desde las paginas web que los describen. Esta funcionalidad es proporcionada
por Go Playground en @l(https://play.golang.org<>play.golang.org), y puede
incrustarse dentro de otras paginas, como la pagina de inicio en
@l(https://golang.org<>golang.org) o las paginas de documentacion provistas
por la herramienta @$(godoc).
Playground hace que sea conveniente llevar a cabo experimentos sencillos para
comprobar la propia comprension de la sintaxis, la semantica, o paquetes de
librerias con programas cortos, y en muchos sentidos toma el lugar de un
@e(bucle de leectura-evaluacion-impresion) (@e(read-eval-print loop) o REPL) de otros
lenguajes. Sus URLs persistentes son excelentes para compartir fragmentos de
codigo con otros, para informar sobre errores o hacer sugerencias.
Construido sobre Playground, el Tour Go en @l(https://tour.golang.org<>tour.golang.org)
es una secuencia de breves lecciones interactivas sobre las ideas y construcciones
basicas de Go, un paseo ordenado atraves del lenguaje.
El principal inconveniente de Playground y el Tour es que permiten que solo
se importen librerias estandar, y muchas funciones de la libreria–por
ejemplo, redes–estan restringidas por razones practicas o de seguridad.
Tambien requiere de acceso a Internet para compilar y ejecutar cada programa.
Asi que para experimentos mas elaborados, tendra que ejecutar programas Go en
su propia computadora. Afortunadamente, el proceso de descarga es sencillo,
por lo que no debe tomar mas de unos minutos obtener la distribucion Go
desde @l(https://golang.org<>golang.org) y empezar a escribir y ejecutar
programas por su cuenta.
Ya que Go es un proyecto de codigo abierto, se puede leer el codigo fuente de
cualquier tipo o funcion en la libreria estandar en @l(https://golang.org/pkg);
el mismo codigo forma parte de la distribucion descargada. Utilicelo para
averiguar como funciona algo, o para responder a preguntas sobre los
detalles, o simplemente para ver como los expertos escriben buen Go.
** Agradecimientos
Rob Pike y Russ Cox, miembros principales del equipo de Go, leyeron el
manuscrito varias veces con mucho cuidado; sus comentarios sobre todo, desde
la eleccion de palabras hasta la estructura general y la organizacion han
sido invaluables. Mientras preparaba la traduccion japonesa, Yoshiki Shibata
iba mucho mas alla del llamado del deber; su ojo meticuloso observo numerosas
inconsistencias en el texto ingles y errores en el codigo. Apreciamos
grandemente revisiones completas y comentarios criticos en el manuscrito
entero de Brian Goetz, Corey Kosak, Arnold Robbins, Josh Bleecher Snyder, y
Peter Weinberger.
Agradecemos a Sameer Ajmani, Ittai Balaban, David Crawshaw, Billy Donohue,
Jonathan Feinberg, Andrew Gerrand, Roberto Griesemer, John Linderman, Minux
Ma, Bryan Mills, Bala Natarajan, Cosmos Nicolaou, Paul Staniforth, Nigel Tao,
y a Howard Trickey por muchas sugerencias utiles. Tambien damos las gracias
a David Brailsford y Raph Levien por sus consejos sobre composicion
tipografica.
Nuestro redactor Greg Doench de Addison-Wesley puso a girar la rueda
originalmente y ha sido de continua ayuda desde entonces. El equipo de
produccion de AW–John Fuller, Dayna Isley, Julie Nahil, Chuti Prasertsith y
Barbara Wood–ha sido excepcional; los autores no podrian esperar un mejor
apoyo.
Alan Donovan desea agradecer a: Sameer Ajmani, Chris Demetriou, Walt
Drummond, y Reid Tatge de Google por haberle dado tiempo para escribir; a Stephen
Donovan, por su consejo y oportuno estimulo; y sobre todo a su esposa Leila
Kazemi, por su entusiasmo y apoyo inquebrantable a este proyecto, a pesar de
las largas horas de distraccion y ausentismo de la vida familiar que ello
implicaba.
Brian Kernighan esta profundamente agradecido a sus amigos y colegas por su
paciencia y autodominio mientras avanzaba lentamente por el camino hacia la
comprension, y especialmente a su esposa Meg, que ha sido infaliblemente
favorable a la escritura de libros y muchas otras cosas.
..quote >
--Nueva York
--Octubre 2015
< quote..
* Capitulo 1 <> Tutorial
Este capitulo es un recorrido por los componentes basicos de Go. Esperamos
proporcionar suficiente informacion y ejemplos para que puedas ponerte en
marcha y hacer cosas utiles lo mas rapido posible. Los ejemplos aqui, y de
hecho en todo el libro, estan dirigidos a tareas que usted podria tener que
hacer en el mundo real. En este capitulo intentaremos darle una muestra de la
diversidad de programas que uno podria escribir en Go, que van desde el simple
procesamiento de archivos y un poco de graficos, a clientes y servidores de
Internet concurrentes. Ciertamente no vamos a explicar todo en el primer
capitulo, pero el estudio de estos programas en un nuevo lenguaje puede ser
una manera eficaz de empezar.
Cuando estas aprendiendo un nuevo lenguaje, hay una tendencia natural a
escribir codigo como lo habrias escrito en un lenguaje que ya conoces. Se
consciente de este sesgo a medida que aprendes Go y trata de evitarlo. Hemos
tratado de ilustrar y explicar como escribir buen Go, asi que usa el
codigo aqui como guia cuando escribas.
** Seccion 1.1 <> Hola, Mundo
Empezaremos con el ya tradicional ejemplo del @"(hola, mundo), que
aparece al comienzo de @e(El lenguaje de programacion C), publicado
en 1978. C es una de las influencias mas directas sobre Go, y @"(hola, mundo)
ilustra una serie de ideas centrales.
..figure > @l(gopl.io/ch1/helloworld/main.go<>gopl.io/ch1/helloworld)
..src > go
package main
import "fmt"
func main() {
fmt.Println("Hello, 世界")
}
< src..
Go es un lenguaje compilado. El conjunto de herramientas de Go convierte el
codigo fuente de un programa y las cosas de las que depende, en instrucciones
en el lenguaje maquina nativo de una computadora. Se puede acceder a estas
herramientas a traves de un unico comando llamado @$(go) que tiene una serie
de subcomandos. El mas simple de estos subcomandos es @$(run), que compila
el codigo fuente de uno o mas archivos de origen cuyos nombres terminan en
@f(.go), lo enlaza con las librerias, y luego, ejecuta el archivo
ejecutable resultante. (Utilizaremos @$($) como el simbolo del sistema en
todo el libro.)
..srci > sh
> go run helloworld.go
< srci..
No es sorprendente que esto imprima
..srci > sh
Hello, 世界
< srci..
Go maneja Unicode de forma nativa, por lo que puede procesar texto en todos
los idiomas del mundo.
Si el programa es mas que un experimento de una sola vez, es probable que
quieras compilarlo una vez y guardar el resultado compilado para su uso
posterior. Esto se hace con @$(go build):
..srci > sh
> go build helloworld.go
< srci..
Esto crea un archivo binario ejecutable llamado @$(helloworld) que se pueden
ejecutar en cualquier momento sin procesamiento adicional:
..srci > sh
> ./helloworld
Hello, 世界
< srci..
Hemos etiquetado cada ejemplo significativo como un recordatorio de que
se puede obtener el codigo fuente del libro desde el repositorio
@l(http://www.gopl.io/<>gopl.io): @l(http://www.gopl.io/ch1/helloworld<>gopl.io/ch1/helloworld)
Si ejecutas @$(go get gopl.io/ch1/helloworld), obtendra el codigo fuente y
lo colocara en el directorio correspondiente. Hay mas informacion sobre este
tema en la @l(#Seccion 2.6) y la @l(#Seccion 10.7).
Hablemos ahora del programa en si. El codigo Go esta organizado en paquetes,
que son similares a librerias o modulos en otros lenguajes. Un paquete se
compone de uno o mas archivos de codigo @f(.go) en un unico directorio que
definen lo que hace el paquete. Cada archivo de codigo inicia con una
declaracion del paquete, aqui es @c(package main), que declara a que paquete
pertenece el archivo, seguido de una lista de otros paquetes que importa, y
luego las declaraciones del programa que se almacenan en ese archivo.
La libreria estandar de Go tiene mas de 100 paquetes para tareas comunes como
entrada y salida, clasificacion y manipulacion de texto. Por ejemplo, el
paquete @c(fmt) contiene funciones para la impresion y entrada de datos con
formato. @c(Println) es una de las funciones basicas de salida en @c(fmt);
imprime uno o mas valores, separados por espacios, con un caracter de
nueva linea al final para que los valores aparezcan como una sola linea de
salida.
El paquete @c(main) es especial. Define un programa ejecutable independiente,
no una libreria. Dentro del paquete @c(main) la @e(funcion) @c(main) tambien
es especial–es donde comienza la ejecucion del programa. Cualquier cosa que
haga @c(main) es lo que hara el programa. Por supuesto, @c(main) sera
normalmente un llamado a las funciones de otros paquetes que hacen gran parte
del trabajo, como la funcion @c(fmt.Println).
Debemos decirle al compilador que paquetes son necesarios para este archivo
de codigo fuente; ese es el papel de la declaracion @c(import) seguida por la
declaracion del @c(paquete). El programa @"(hola, mundo) utiliza solo una
funcion de otro paquete, pero en la mayoria de los programas se importaran mas
paquetes.
Debes importar exactamente los paquetes que necesitas. Un programa no compilara
si hay importaciones que faltan o si son innecesarias. Este estricto
requisito impide que las referencias a paquetes no utilizados se acumulen a
medida que los programas evolucionan.
Las declaraciones @c(import) deben ir luego de la declaracion @c(package).
Despues de eso, un programa consiste en la declaracion de funciones,
variables, constantes y tipos (introducidos por las palabras clave @c(func),
@c(var), @c(const), y @c(type)); en su mayor parte, el orden de las
declaraciones no importa. Este programa es lo mas corto posible, ya que
declara solo una funcion, que a su vez solo llama a otra funcion. Para
ahorrar espacio en la presentacion de ejemplos, a veces no mostramos las
declaraciones @c(package) e @c(import), pero estaran en el codigo del archivo
y deben estar ahi para compilar el codigo.
Una declaracion de funcion consiste en la palabra clave @c(func), el nombre
de la funcion, una lista de parametros (vacia para @c(main)), una lista de
resultados (aqui tambien vacia), y el cuerpo de la funcion–las declaraciones
que definen lo que hace–encerradas entre llaves. Vamos a echar un vistazo mas
de cerca a las funciones en el @l(#Capitulo 5).
Go no requiere punto y coma al final de las sentencias o declaraciones,
excepto donde aparecen dos o mas en la misma linea. En efecto, las nuevas
lineas que siguen ciertas palabras se convierten en punto y coma, por lo que
cuando se colocan nuevas lineas se colocan en funcion del correcto analisis
del codigo Go. Por ejemplo, la llave de apertura @c({) de la funcion, debe
estar en la misma linea, que el final de la declaracion @c(func), no en una
linea distinta, y en la expresion @c(x + y), se permite un salto de linea
despues, pero no antes del operador @c(+).
Go toma una fuerte postura sobre el formato del codigo. La herramienta @$(gofmt)
reescribe el codigo en el formato estandar, y el subcomando @$(fmt) de la
herramienta @$(go) aplica @$(gofmt) a todos los archivos en el paquete
especificado, o por defecto, a los que estan en el directorio actual. Se ha
ejecutado @$(gofmt) sobre todos los archivos de codigo fuente en el libro, y
usted debe optener el habito de hacer lo mismo con su propio codigo. Declarar
un formato estandar por mandato elimina un monton de debate inutil sobre
trivialidades y, lo que es mas importante, permite una variedad de
transformaciones automatizadas de codigo fuente que serian imposibles si se
permitiera el formato arbitrario.
Muchos editores de texto pueden ser configurados para ejecutar @$(gofmt) cada
vez que se guarda un archivo, por lo que su codigo fuente siempre tendra el
formato apropiado. Una herramienta relacionada, @$(goimports), ademas,
gestiona la insercion y extraccion de las declaraciones de importacion, segun
sea necesario. No es parte de la distribucion estandar pero se puede obtener
con este comando:
..srci > sh
> go get golang.org/x/tools/cmd/goimports
< srci..
Para la mayoria de los usuarios, la forma habitual de descargar y construir
paquetes, ejecutar pruebas, mostrar su documentacion, y asi sucesivamente, es
con la herramienta @$(go), que veremos en la @l(#Seccion 10.7).
** Seccion 1.2 <> Argumentos de Linea de Comandos
La mayoria de los programas procesan alguna entrada para producir alguna
salida; que es mas o menos la definicion de computacion. Pero, ¿como un
programa obtiene datos de entrada sobre los que operar? Algunos programas
generan sus propios datos, pero mas a menudo, la entrada proviene de una
fuente externa: un archivo, una conexion de red, la salida de otro programa,
un usuario en un teclado, argumentos de linea de comandos o similares. En los
siguientes ejemplos se discutiran algunas de estas alternativas, comenzando con
argumentos de linea de comandos.
El paquete @c(os) proporciona funciones y otros valores para relacionarse con
el sistema operativo de una manera independiente de la plataforma. Los
argumentos de linea de comandos estan disponibles para un programa en una
variable denominada @c(Args) que forma parte del paquete @c(os); por lo tanto
su nombre en cualquier lugar fuera del paquete @c(os) es @c(os.Args).
La variable @c(os.Args) es un @e(slice) de @c(strings). Los slices son una
nocion fundamental en Go, y hablaremos mucho mas sobre ellos pronto. Por
ahora, piensa en un slice como una secuencia @c(s) de elementos de un arreglo
de tamaño dinamico, donde los elementos individuales pueden accederse como
@c(s[i]) y una subsecuencia contigua como @c(s[m:n]). El numero de elementos esta
dado por @c[len(s)]. Como en la la mayoria de los otros lenguajes de
programacion, toda indexacion en Go utiliza intervalos @e(semiabiertos)
que incluyen el primer indice, pero no incluyen el ultimo, ya que simplifica
la logica. Por ejemplo, el slice @c(s[m:n]), donde @c[0 ≤ m ≤ n ≤ len(s)],
contiene @c(n-m) elementos.
El primer elemento de @c(os.Args), @c(os.Args[0]), es el nombre del comando
en si; los otros elementos son los argumentos que se ofresieron al programa
cuando se inicio la ejecucion. Una expresion de la forma @c(s[m:n]) produce
un slice que hace referencia a los elementos entre @c(m) y @c(n-1), por lo
que los elementos que necesitamos para nuestro siguiente ejemplo corresponden
al slice @c{os.Args[1:len(os.Args)]}. Si @c(m) o @c(n) se omite, el valor
predeterminado es 0 o @c[len(s)], respectivamente, por lo que se puede
abreviar el slice deseado como @c(os.Args[1:]).
Aqui esta una implementacion del comando @$(echo) de Unix, que imprime sus
argumentos de linea de comandos en una sola linea. Importa dos paquetes, que
se dan como una lista entre parentesis en lugar de como declaraciones de
importacion individuales. Cualquiera de las formas es legal, pero
convencionalmente se utiliza el formato de lista. El orden de las
importaciones no importa; la herramienta @$(gofmt) ordena los nombres de los
paquetes en orden alfabetico. (Cuando hay varias versiones de un ejemplo, a
menudo las numeraremos para que pueda estar seguro de cual estamos hablando.)
..figure > @l(gopl.io/ch1/echo1/main.go<>gopl.io/ch1/echo1)
..src > go
// Echo1 imprime sus argumentos de linea de comandos
package main
import (
"fmt"
"os"
)
func main() {
var s, sep string
for i := 1; i < len(os.Args); i++ {
s += sep + os.Args[i]
sep = " "
}
fmt.Println(s)
}
< src..
Los comentarios comienzan con @c(//). Todo el texto desde @c(//) hasta el
final de la linea es el comentario para los programadores y es ignorado por
el compilador. Por convencion, describimos cada paquete en un comentario
inmediatamente anterior a su declaracion del paquete; para un paquete
@c(main), este comentario es una o varias frases completas que describen el
programa en su conjunto.
La declaracion @c(var) declara dos variables @c(s) y @c(sep), de tipo
@c(string). Una variable se puede inicializar como parte de su declaracion.
Si no se inicia de forma explicita, se inicializa de forma implicita al
@e(valor cero) para su tipo, que es @c(0) para los tipos numericos y la cadena
vacia @c("") para strings. Asi, en este ejemplo, la declaracion implicita
inicializa @c(s) y @c(sep) como cadenas vacias. Tendremos mas que decir
acerca de las variables y las declaraciones en el @l(#Capitulo 2).
Para los numeros, Go proporciona los operadores aritmeticos y logicos
habituales. Sin embargo, cuando se aplica a las cadenas, el operador @c(+)
@e(concatena) los valores, por lo que la expresion
..src > go
sep + os.Args[i]
< src..
representa la concatenacion de las cadenas @c(sep) y @c(os.Args[i]). La
declaracion que usamos en el programa,
..src > go
s += sep + os.Args[i]
< src..
es una @e(sentencia de asignacion) que concatena el antiguo valor de @c(s) con @c(sep)
y @c(os.Args[i]) y lo asigna de nuevo a @c(s); es equivalente a
..src > go
s = s + sep + os.Args[i]
< src..
El operador @c(+=) es un @e(operador de asignacion). Cada operador aritmetico y
logico como @c(+) o @c(*) tiene un operador de asignacion correspondiente.
El programa @$(echo) podria haber impreso su salida en un bucle de una sola
pieza a la vez, pero en esta version, en su lugar se acumula una cadena
añadiendo repetidamente nuevo texto hasta el final. La cadena de @c(s)
comienza su vida vacia, es decir, con el valor @c(""), y cada ciclo a traves
del bucle añade un poco de texto a ella; despues de la primer iteracion,
tambien se inserta un espacio para que cuando el bucle termine, haya
un espacio entre cada argumento. Este es un proceso cuadratico que podria ser
costoso si el numero de argumentos es grande, pero para @$(echo), eso es poco
probable. Vamos a mostrar una serie de versiones mejoradas de @$(echo) en
este capitulo y el siguiente para hacer frente a cualquier ineficiencia real.
La variable de indice @c(i) del bucle se declara en la primer parte del bucle
@c(for). El simbolo @c(:=) es parte de una @e(declaracion de variables
compacta), una sentencia que declara una o mas variables y les da los tipos
apropiados basados en los valores del inicializador; hay mas informacion al
respecto en el proximo capitulo.
La declaracion de incremento @c(i++) añade 1 a @c(i); que es equivalente a
@c(i += 1), que es a su vez equivalente a @c(i = i + 1). Hay una declaracion
de decremento correspondiente @c(i--) que resta 1. Estas son declaraciones,
no expresiones como lo son en la mayoria de los lenguajes en la familia C,
por lo que @c(j = i++) es ilegal, y solamente son de sufijo, asi @c(--i)
tampoco es legal.
El bucle @c(for) es la unica sentencia de bucle en Go. Tiene varias formas,
una de las cuales se ilustra aqui:
..src > go
for inicializacion; condicion; incremento {
// cero o mas declaraciones
}
< src..
Los parentesis no se utilizan nunca alrededor de los tres componentes de un
bucle @c(for). Sin embargo, las llaves son obligatorias, y la llave de apertura
deben estar en la misma linea que la declaracion @c(incremento).
La declaracion opcional @c(inicializacion) se ejecuta antes de que comience
el bucle. Si esta presente, debe ser una simple declaracion, es decir, una
declaracion de variables compacta, una declaracion de incremento o asignacion, o
una llamada a funcion. La @c(condition) es una expresion booleana que se
evalua en al inicio de cada iteracion del bucle; si se evalua como @c(true),
las declaraciones controladas por el bucle se ejecutan. La declaracion
@c(incremento) se ejecuta despues del cuerpo del bucle, luego la
@c(condicion) se evalua de nuevo. El bucle termina cuando la condicion se
convierte en falsa.
Cualquiera de estas partes puede omitirse. Si no hay @c(inicializacion) y
ningun @c(incremento), el punto y coma tambien pueden omitirse:
..src > go
// un tradicional bucle "while"
for condicion {
// ...
}
< src..
Si la condicion se omite por completo en cualquiera de estas formas, por
ejemplo en
..src > go
// un tradicional bucle infinito
for {
// ...
}
< src..
el bucle es infinito, aunque los bucles de esta forma se pueden terminar de
alguna otra manera, como una declaracion @c(break) o @c(return).
Otra forma en que el bucle @c(for) itera, es sobre un @e(rango) de valores de
un tipo de datos como un string o un slice. Para ilustrar esto, he aqui una
segunda version de @$(echo):
..figure > @l(gopl.io/ch1/echo2/main.go<>gopl.io/ch1/echo2)
..src > go
// Echo2 imprime sus argumentos de linea de comandos
package main
import (
"fmt"
"os"
)
func main() {
s, sep := "", ""
for _, arg := range os.Args[1:] {
s += sep + arg
sep = " "
}
fmt.Println(s)
}
< src..
En cada iteracion del bucle, @c(range) produce un par de valores: el indice y
el valor del elemento en ese indice. En este ejemplo, no necesitamos el
indice, pero la sintaxis de un bucle @c(range) requiere que si tratamos con
el elemento, debemos tratar tambien con el indice. Una idea seria asignar el
indice a una variable temporal, como @c(temp) y pasar por alto su valor, pero
Go no permite tener variables locales sin utilizar, por lo que esto daria
lugar a un error de compilacion.
La solucion es utilizar el @e(identificador en blanco), cuyo nombre es @c(_)
(esto es, un guion bajo). El identificador en blanco puede utilizarse siempre
que la sintaxis requiera un nombre de variable, pero la logica del programa
no lo haga, por ejemplo para descartar un indice no deseado del bucle cuando
solo necesitamos el valor del elemento. La mayoria de los programadores Go
probablemente usarian @c(range) y @c(_) para escribir el programa @$(echo)
anterior, ya que la indexacion sobre @c(os.Args) es implicita, no explicita,
y por lo tanto mas facil de hacerlo bien.
Esta version del programa utiliza una declaracion compacta de variables para
declarar e inicializar @c(s) y @c(sep), pero podria igualmente haber declarado las
variables por separado. Hay varias maneras de declarar una variable string;
Todas estas son equivalentes:
..src > go
s := ""
var s string
var s = ""
var s string = ""
< src..
Por que preferirias una forma sobre otra? El primer formato, una
declaracion de variable compacta, es la mas breve, pero solo puede utilizarse
dentro de una funcion, no para variables de nivel de paquete. La segunda
forma se basa en la inicializacion por defecto al valor cero para strings,
que es @c(""). La tercera forma se utiliza raramente excepto cuando se
declaran multiples variables. La cuarta forma es explicita sobre el tipo de
la variable, que es redundante cuando es el mismo que el del valor inicial
pero necesario en otros casos donde no son del mismo tipo. En la practica,
generalmente debe utilizar una de las dos primeras formas, con inicializacion
explicita para decir que el valor inicial es importante e implicita para
decir que el valor inicial no importa.
Como se señalo anteriormente, cada iteracion alrededor del bucle, la cadena
@c(s) obtiene contenidos completamente nuevos. La declaracion @c(+=) crea una
nueva cadena mediante la concatenacion de la cadena antigua, un caracter de
espacio, y el siguiente argumento, a continuacion, asigna la nueva cadena a
@c(s). El contenido antiguo del @c(s) ya no estan en uso, por lo que sera
recolectado por el recolector de basura a su debido tiempo.
Si la cantidad de datos involucrados es grande, esto podria ser costoso. Una
solucion mas simple y mas eficiente seria utilizar la funcion @c(Join) del
paquete @c(strings):
..figure > @l(gopl.io/ch1/echo3/main.go<>gopl.io/ch1/echo3)
..src > go
func main() {
fmt.Println(strings.Join(os.Args[1:], " "))
}
< src..
Por ultimo, si no nos interesa el formato, y solo queremos ver los valores,
tal vez para depuracion, podemos dejar que @c(Println) formatee el resultado por
nosotros:
..src > go
fmt.Println(os.Args[1:])
< src..
El resultado de esta sentencia es como la que se puede conseguir mediante
@c(strings.Join), pero con corchetes al rededor. Cualquier slice se puede
imprimir de esta manera.
@b(Ejercicio 1.1): Modifica el programa @$(echo) para imprimir tambien
@c(os.Args[0]), el nombre del comando que lo invoco.
@b(Ejercicio 1.2): Modifica el programa @$(echo) para imprimir el indice y el
valor de cada uno de sus argumentos, uno por linea.
@b(Ejercicio 1.3): Experimenta para medir la diferencia en el tiempo de
funcionamiento entre nuestras versiones potencialmente ineficientes y el que
utiliza @c(strings.Join). (La @l(#Seccion 1.6) ilustra parte del paquete
@c(time), y la @l(#Seccion 11.4) muestra como escribir pruebas de referencia
para la evaluacion sistematica del rendimiento.)
** Seccion 1.3 <> Encontrar lineas duplicadas
Los programas para copiar archivos, imprimir, buscar, clasificar, contar y
similares tienen una estructura parecida: un bucle sobre la entrada, algun
calculo sobre cada elemento y generacion de salida al vuelo o al final.
Mostraremos tres variantes de un programa llamado @$(dup); se inspira en
parte por el comando Unix @$(uniq), que mira las lineas duplicadas
adyacentes. Las estructuras y paquetes utilizados son modelos que se pueden
adaptar facilmente.
La primer version de @$(dup) imprime cada linea que aparece mas de una vez en
la entrada estandar, precedido por su recuento. Este programa presenta la
declaracion @c(if), el tipo de datos @c(map) y el paquete @c(bufio).
..figure > @l(gopl.io/ch1/dup1/main.go<>gopl.io/ch1/dup1)
..src > go
// Dup1 imprime el texto de cada linea que aparece mas de
// una vez en la entrada estandar, precedida por su recuento.
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
counts := make(map[string]int)
input := bufio.NewScanner(os.Stdin)
for input.Scan() {
counts[input.Text()]++
}
// NOTA: ignorando posibles errores de input.Err ()
for line, n := range counts {
if n > 1 {
fmt.Printf("%d\t%s\n", n, line)
}
}
}
< src..
Al igual que con @c(for), nunca se usan parentesis alrededor de la
declaracion de la condicion @c(if), pero se requieren llaves para el
cuerpo. Puede haber una parte @c(else) opcional que se ejecute si la
condicion es falsa.
Un @e(mapa) contiene un conjunto de pares clave/valor y proporciona
operaciones de tiempo constante para almacenar, recuperar, o comprobar un
elemento en el conjunto. La clave puede ser de cualquier tipo cuyos valores
puedan compararse con @c(==), siendo strings el ejemplo mas comun; el valor
puede ser de cualquier tipo en absoluto. En este ejemplo, las claves son
@c(string)s, y los valores son @c(int)s. La funcion incorporada @c(make) crea
un nuevo mapa vacio; tiene otros usos tambien. Los mapas se discuten
extensamente en la @l(#Seccion 4.3).
Cada vez que @$(dup) lee una linea de entrada, la linea se utiliza como una
clave en el mapa y se incrementa el valor correspondiente. La declaracion
@c{counts[input.Text()]++} es equivalente a estas dos afirmaciones:
..src > go
line := input.Text()
counts[line] = counts[line] + 1
< src..
No es un problema, si el mapa aun no contiene esa clave. La primera vez que
se ve una nueva linea, la expresion @c(counts[line]) en el lado derecho se
evalua al valor cero para su tipo, que es 0 para @c(int).
Para imprimir los resultados, utilizamos otro bucle de repeticion @c(for)
basado en @c(range), esta vez sobre el mapa @c(counts). Como antes, cada
iteracion produce dos resultados, una clave y el valor del elemento del mapa
para esa clave. El orden de la iteracion del mapa no es especifico, en la
practica es aleatorio, variando de una ejecucion a otra. Este diseño es
intencional, ya que impide que los programas se basen en cualquier orden
particular donde no se garantiza ninguno.
El paquete @c(bufio), ayuda a que la entrada y salida sea eficiente y
conveniente. Una de sus caracteristicas mas utiles es un tipo llamado
@c(Scanner) que lee la entrada y la rompe en lineas o palabras; a menudo es
la manera mas facil de procesar la entrada que llega naturalmente en lineas.
El programa utiliza una breve declaracion de variables para crear una nueva
variable de entrada que hace referencia a @c(bufio.Scanner):
..src > go
input := bufio.NewScanner(os.Stdin)
< src..
El escaner lee de la entrada estandar del programa. Cada llamada a
@c[input.Scan()] lee la siguiente linea y elimina el caracter de nueva linea
al final; el resultado puede ser recuperado llamando a @c[input.Text()]. La
funcion @c(Scan) devuelve @c(true) si hay una linea y @c(false) cuando no hay
mas entrada.
La funcion @c(fmt.Printf), como @c(printf) en C y otros lenguajes, produce
una salida con formato de una lista de expresiones. Su primer argumento es
una cadena de formato que especifica como deben formatearse los argumentos
posteriores. El formato de cada argumento esta determinado por un caracter de
conversion, una letra siguiendo un signo de porcentaje. Por ejemplo, @c(%d)
formatea un operando entero usando la notacion decimal, y @c(%s) se expande
para el valor de un operando de cadena.
@c(Printf) tiene mas de una docena de estas conversiones, que los
programadores de Go llaman @e(verbos). Esta tabla esta lejos de ser una
especificacion completa, pero ilustra muchas de las caracteristicas que estan
disponibles:
+------------------------+--------------------------------------------------------------------+
| @c(%d) | entero decimal |
+------------------------+--------------------------------------------------------------------+
| @c(%x), @c(%o), @c(%b) | entero en hexadecimal, octal, binario |
+------------------------+--------------------------------------------------------------------+
| @c(%f), @c(%g), @c(%e) | numero de coma flotante: 3.141593 3.141592653589793 3.141593e + 00 |
+------------------------+--------------------------------------------------------------------+
| @c(%t) | booleano: @c(true) o @c(false) |
+------------------------+--------------------------------------------------------------------+
| @c(%c) | runa (punto de codigo Unicode) |
+------------------------+--------------------------------------------------------------------+
| @c(%s) | string |
+------------------------+--------------------------------------------------------------------+
| @c(%q) | citar string @c("abc") o runa @c('c') |
+------------------------+--------------------------------------------------------------------+
| @c(%v) | cualquier valor en un formato natural |
+------------------------+--------------------------------------------------------------------+
| @c(%T) | cualquier tipo de valor |
+------------------------+--------------------------------------------------------------------+
| @c(%%) | signo literal de porcentaje (sin operando) |
+------------------------+--------------------------------------------------------------------+
El formato de cadena en @c(dup1) tambien contiene una tabulacion @c(\t) y un
salto de linea @c(\n). Los literales de cadena pueden contener tales
@e(secuencias de escape) para la representacion de caracteres de otra manera
invisibles. @c(Printf) no escribe una nueva linea por defecto. Por
convencion, las funciones de formato cuyos nombres terminan en @c(f), tales
como @c(log.Printf) y @c(fmt.Errorf), utilizan las reglas de formato de
@c(fmt.Printf), mientras que aquellas cuyos nombres terminan en @c(ln) como
@c(Println), formatean sus argumentos con @c(%v), seguido por una nueva
linea.
Muchos programas leen ya sea a partir de su entrada estandar, como
arriba, o de una secuencia de archivos con nombre. La proxima version
de @$(dup) puede leer desde la entrada estandar o manejar una lista de
nombres de archivos, utilizando @c(os.Open) para abrir cada uno de ellos:
..figure > @l(gopl.io/ch1/dup2/main.go<>gopl.io/ch1/dup2)
..src > go
// Dup2 imprime el recuento y el texto de las lineas que aparecen mas de una vez
// en la entrada. Se lee desde stdin o desde una lista de archivos con nombre.
package main