Este documento introduce el lenguaje de programación Go. Go es un lenguaje compilado pero con compilaciones muy rápidas, fuertemente tipado y con comprobaciones estrictas en tiempo de compilación. Go fue lanzado en 2012 y ofrece ventajas como velocidad de ejecución, concurrencia y facilidad de despliegue. El documento discute las características y ventajas de Go para el desarrollo de software.
3. Razones para usar un lenguaje de scripting
Velocidad de desarrollo.
Expresividad.
No hay necesidad de compilación.
Recolección de basura.
Abstracciones de alto nivel.
¿Despliegue?
4. Razones para usar un lenguaje compilado
Velocidad de ejecución.
Tipado estático.
Comprobaciones en tiempo de compilación.
¿Despliegue?
5. Y si...
Legible y claro.
Lenguaje compilado, pero de muy rápida compilación.
Comprobaciones estrictas en tiempo de compilación.
Fuertemente tipado.
Recolección de basura.
Facilidad de despliegue.
Y muchas otras particularidades inusuales en los lenguajes más populares, útiles
para el desarrollador.
7. Golang, un nuevo lenguaje
No ha habido grandes avances en lenguajes de programación... ¡en casi una
década!
PHP nació en el año 1995
Ruby también fue creado en 1995
Node.js...
8. Go te ayuda a desarrollar correctamente
Sintaxis concisa.
Diseñado para ser eficiente en tiempo de desarrollo.
Rápido en tiempo de ejecución.
Es un lenguaje concurrente, y con un buen soporte para paralelización.
Soporta tests y benchmarks de forma nativa.
9. Go te ayuda a desarrollar cómodamente
Soporta nativamente Unicode.
Recolector de basura.
Devolución de múltiples valores.
Las funciones son tipos de primer orden.
Elimina lo que muchos consideran necesario: objetos e interfaces. En su lugar,
presenta alternativas diferentes.
10. Go te obliga a programar bien
Comprobaciones muy estrictas en tiempo de compilación.
Comprobación estricta de tipos, no existen "tipos compatibles".
No existe el tipo "float".
Desde Go 1.0, no se garantiza el orden de iteración sobre mapas.
11. Go te insta a que tu código sea legible.
No existen excepciones, sólo errores excepcionales.
No se permiten imports o variables no usadas.
Uso de punteros sin aritmética de punteros.
Se prohiben expresiones que puedan resultar en código ilegible. Por ejemplo:
vr =vr+
a2
a+
13. Un ejemplo de C
it(((f)it)dul)(la)
n ***3(n)(obe)fot;
f
3
*3
f
(f)
*3( )
(f)it
*3(n)
**3(n)
(f)it
((f)it)
**3(n)(
)
((f)it)dul)
**3(n)(obe
***3(n)(obe
((f)it)dul)
(((f)it)dul)(
***3(n)(obe)
)
(((f)it)dul)(la)
***3(n)(obe)fot
it(((f)it)dul)(la)
n ***3(n)(obe)fot
- f
- 3
- i apitr
- s
one
- t afnto
- o
ucin
- tkn a itprmtr
aig n n aaee
- rtrigapitr
eunn
one
- t afnto
o
ucin
tkn adul prmtr
aig
obe aaee
rtrigapitr
eunn
one
t afnto
o
ucin
tkn afotprmtr
aig
la aaee
rtrigit
eunn n
StackOverflow(http://stackoverflow.com/questions/10758811/c-syntax-for-functions-returning-function-pointers)
14.
15. El mismo ejemplo en Go
fn (n)fn(la6)fn(la3)it
uc it ucfot4 ucfot2 n
vs
it(((f)it)dul)(la)
n ***3(n)(obe)fot
16. Un ejemplo de Java
pbi sai fnlSrn raFl(tigflnm){
ulc ttc ia tig edieSrn ieae
SrnBidrs =nwSrnBidr)
tigule b
e tigule(;
ty{
r
BfeeRae b =nwBfeeRae(e FlRae(ieae)
ufrdedr r
e ufrdedrnw ieedrflnm);
itra =0
n ed
;
ca[ bfe =nwca[04;
hr] ufr
e hr12]
wie - ! (ed=b.edbfe,0 bfe.egh)){
hl( 1 = ra
rra(ufr , ufrlnt)
s.pedbfe,0 ra)
bapn(ufr , ed;
}
b.ls(;
rcoe)
}cth(Oxeto e {
ac IEcpin )
Lge"TP,"edtem,e;
o.(HT" raSra" )
CitrimlgadeEcpine;
rtecs.oHnldxeto()
rtr nl;
eun ul
}
rtr s.otig)
eun btSrn(;
}
17. El mismo ejemplo en Go
dt,er: iui.edie"ie)
aa r = otlRaFl(fl"
Sin usar ioutil:
fn raFl(ieaesrn)(tig err {
uc edieflnm tig srn, ro)
bf: btsNwufrnl
u = ye.eBfe(i)
f er: o.pnflnm)
, r = sOe(ieae
i nl! er{
f i = r
rtr `,er
eun ` r
}
dfrfCoe)
ee .ls(
_ er=i.oybf f
, r
oCp(u, )
i nl! er{
f i = r
rtr `,er
eun ` r
}
rtr srn(u.ye()
eun tigbfBts)
}
18. Golang soporta Unicode totalmente
pcaemi
akg an
ipr "m"
mot ft
fn mi( {
uc an)
ಠ益ಠ, ಠ_ 東京事変 : ` р в т , f t P i t n ` и `
ಠ,
= Пие` m.rnl, мр
}
ಠ_ ಠ益ಠ, 東京事変)
ಠ(
Run
22. int y bool
it un,it,un8 it6 un1,it2 un3,it4 un6.
n, it n8 it, n1, it6 n3, it2 n6, it4
Desde Go 1.1, int es de 64 bits cuando se ejecuta en CPU de 64 bits.
Personalmente, me gusta más especificar siempre el tamaño.
vrxun3 =3
a
it2
O también:
x: un3()
= it23
Para booleanos: true, false y operadores a la C.
23. Ejemplos
Ejemplo incorrecto
fn mi( {
uc an)
vrxun3 =4
a
it2
2
vryun8=x
a
it
ftPit(yvl %.n,y
m.rnf" ae d" )
}
Run
¿Y ahora?
fn mi( {
uc an)
vrxun3 =4
a
it2
2
vryun =x
a
it
ftPit(yvl %.n,y
m.rnf" ae d" )
}
Run
24. Más ejemplos
fn mi( {
uc an)
x: tu
= re
i x= tu {
f
= re
ftPitn`eddr`
m.rnl(Vraeo)
}es {
le
ftPitn`as`
m.rnl(Flo)
}
}
Run
De otra forma:
fn mi( {
uc an)
sic {
wth
cs tu:
ae re
ftPitn`stu`
m.rnl(e re)
cs fle
ae as:
ftPitn`sfle)
m.rnl(e as`
dfut
eal:
ftPitn``
m.rnl(?)
}
}
Run
25. Otros tipos numéricos
No se define un tipo float. En su lugar, existen float32 y float64
vr(
a
xfot2=2
la3
mfot4=6032
la6
.2e3
)
Números complejos. Si, Go soporta números complejos: complex64 y complex128.
fn mi( {
uc an)
vrzcmlx2 =cpxPwmt.,-imt.i
a
ope18
ml.o(ahE 1*ahP)
ftPit(z=%.n,z
m.rnf"
f" )
}
Run
27. Array
Se puede declarar un array de cualquier tipo, nativo o no.
vr(
a
x[]n3
5it2
y[0[]nefc{
1]2itrae}
)
No son referencias, por lo que se copia la memoria al pasarlos a una función.
Recuerda: Go siempre pasa los parámetros por valor.
Recuerda: Go siempre inicializa todo a su zero-value.
28. Array
Nos podemos ahorrar escribir el tamaño usando "..." cuando se especifica un literal.
fn mi( {
uc an)
vrx[]n
a
3it
y: [.]la3{,2 4
= ..fot23 , }
ftPitnx y
m.rnl(, )
}
Run
¡Re-slicing!
fn mi( {
uc an)
x: [.]n{,2 3 4 5
= ..it1 , , , }
ftPitnx:] x2] x24)
m.rnl([3, [:, [:]
}
Dado que el tamaño se especifica en la declaración, son inmutables.
Run
29.
30. Array o slice, esa es la cuestión
Go proporciona un wrapper sobre los arrays inmutables, lo que llama slice.
vrx[it=mk(]n,3
a
]n
ae[it )
y: [it1 2 3
= ]n{, , }
vs
vrx[]n
a
3it
y: [.]n{,2 3
= ..it1 , }
Un slice es una referencia al array subyacente, por lo que siguen siendo inmutables.
Dado que son una referencia, su zero-value es nil.
Para crear un slice, se puede utilizar un literal, o bien utilizar la función make().
31. Slice
Utilizando make(), podemos especificar un tamaño y una capacidad inicial.
Tamaño: Número de elementos que el slice contiene actualmente.
Capacidad: tamaño del array subyacente.
x: mk(]la3,3 1)
= ae[fot2 , 0
Por defecto, la capacidad se supone igual al tamaño, por lo que no es necesario
indicarla.
Para añadir uno o varios elementos, se utiliza la función append:
x=apn(,2
pedx )
x=apn(,3 4 5
pedx , , )
32. Diferencia entre array y slice
Un slice también puede ser "re-sliced". Esto no cambia mas que el puntero hacia el
array, no copia memoria.
Ambos se comportan como se espera con las funciones len, cap y copy.
Pero además, un slice nos ofrece la posibilidad de añadir elementos, ampliando la
capacidad del array. Pista: realloc.
34. Mapas
Como un HashMap de Java, o un Hash de Ruby.
Mapea cualquier valor comparable a cualquier cosa.
vrmmpsrn]nefc{
a
a[tigitrae}
Aquí, es clásico utilizar interface{} del mismo modo que Object en Java.
Al igual que los array y slices, son iterables. ¡Pero ojo! NO se garantiza el orden.
Del mismo modo que los slices, su zero-value es nil.
fn mi( {
uc an)
m: mk(a[tig[it2
= aempsrn]]n3)
m`oa]=[it21 2
[hl`
]n3{, }
m`to]=[it23 4
[or`
]n3{, }
frky vle: rnem{
o e, au = ag
ftPitnky vle
m.rnl(e, au)
}
}
Run
35. Mapas
cnt(
os
CUI
HL
=1
KLCUI=13*CUI
IOHL
e
HL
MGCUI=16*CUI
EAHL
e
HL
)
fn mi( {
uc an)
mlnmtr: mk(a[tigit2
oooee = aempsrn]n3)
mlnmtr`uet]=4 *MGCUI
oooee[Cbr`
0
EAHL
ftPitnmlnmtr`uet] mlnmtr`odeg]
m.rnl(oooee[Cbr`, oooee[Zibr`)
}
Run
O podemos comprobar si existe un mapping.
fn mi( {
uc an)
mlnmtr: mpsrn]n3{Cbr` 4 *MGCUI
oooee = a[tigit2`uet: 0
EAHL}
i v o : mlnmtr`odeg] o {
f , k = oooee[Zibr`; k
ftPitnv
m.rnl()
}es {
le
ftPitn` UN CO`
m.rnl(Y
O OL)
}
}
Run
37. string
Los strings son inmutables.
vrvral srn ="aea
a aibe tig
cdn"
En el fondo, no es más que un []byte, por lo que puede contener cualquier
contenido arbitrario.
Como todos los tipos compuestos en Go, es iterable.
En Go no hay char, hay rune, que representan codepoints unicode.
Rune no es más que un alias de int32.
38. Operadores
Los _string_'s no son referencias. Recuerda: sólo slices y maps lo son.
Operaciones habituales a través de los paquetes string y unicode.
Literales con "cadena" o c d n .
aea
fn mi( {
uc an)
ftPitn`soeu srn`
m.rnl(Et snn tig)
ftPitn"soeor srn"
m.rnl(Et snto tig)
}
Run
Se puede iterar sobre ellos, rune a rune.
fn mi( {
uc an)
sr: `oa пие!
t = Hl, рвт`
fri r: rnesr{
o ,
= ag t
ftPit(sr%)'c" i r
m.rnf"t(d=%'n, , )
}
}
Run
43. Duck typing
"Si camina como un pato, nada como un pato y suena como un pato, es un pato."
tp Srne itrae{
ye tigr nefc
Srn( srn
tig) tig
}
Cualquier tipo que implemente ese método "de facto", puede ser utilizado como
un Stringer.
tp Vco []n3
ye etr 3it2
fn ( Vco)Srn( srn {
uc v etr tig) tig
rtr ftSrnf`=%,%,%),v0,v1,v2)
eun m.pit(v(d d d` [] [] []
}
fn mi( {
uc an)
x: Vco{,2 3
= etr1 , }
ftPitnx
m.rnl()
}
Run
44. Structs
Combinado con los zero-values, los literales de structs son muy prácticos.
tp rslTp src {
ye eutye tut
Ipesos un6 `sn"mrsin"
mrsin
it4 jo:ipesos`
Ves
iw
un6 `sn"iw"
it4 jo:ves`
Itrcin fot2`sn"neatosoiepy`
neatos la3 jo:itrcin,mtmt"
}
rt: rslTp{mrsin:m}
e = eutyeIpesosip
Cuidado: Los campos de structs que comienzan por mayúscula, se consideran
"public", y el resto, "private".
Además, como en el ejemplo, se pueden "anotar", para definir otras propiedades
como, por ejemplo, el nombre del campo cuando se convierta a JSON.
46. ¡Structs!
Aunque Golang no es un lenguaje orientado a objetos, pero aún así permite
"herencia múltiple", el llamado "embedding".
tp Aia src {
ye nml tut
Nmr srn
obe tig
}
tp Msoasrc {
ye act tut
Ahcal bo
cuhbe ol
}
tp Prosrc {
ye er tut
Aia
nml
Msoa
act
Rz TpRz
aa ioaa
}
Podemos invocar cualquier método definido sobre "Animal" sobre un objeto de
tipo Perro, así como acceder directamente a sus campos.
p: ProNmr:"ay,Ahcal =tu}
= er{obe Yk" cuhbe
re
47. Funciones
Como hemos visto, es posible escribir funciones que devuelvan varios parámetros.
No sólo es posible, sino que es ampliamente utilizado y se considera parte del "Gostyle".
Además, estos valores de retorno pueden tener opcionalmente un nombre.
fn pwxfot4 (2fot4 x fot4 {
uc o( la6) x la6, 3 la6)
x =x*x
2
x =x *x
3
2
rtr
eun
}
fn mi( {
uc an)
ftPitnpw2)
m.rnl(o()
}
Run
48. Funciones
Del mismo modo, se pueden declarar y asignar varias variables a la vez.
fn pwxfot4 (2 x fot4 eerr {
uc o( la6) x, 3 la6,
ro)
i x>1 {
f
0
rtr 0 0 ftErr(E vlrx% e dmsaogad" x
eun , , m.rof"l ao =f s eaid rne, )
}
rtr xx xxx nl
eun *, **, i
}
fn mi( {
uc an)
x y er: pw4
, , r = o()
i er! nl{
f r = i
ftPit(ERR %.n,er
m.rnf"RO: v" r)
}es {
le
ftPitnx y
m.rnl(, )
x y=y x
,
,
ftPitnx y
m.rnl(, )
}
}
Run
49. Closures
Una de las mejores características del lenguaje, es su definición de las funciones
como un tipo de dato más.
Además, las funciones "literales" son closures, de modo que capturan cualquier
variable que haya en su scope y pueden acceder a ella como si fuera propia.
fn Gnrtrxit fn( it{
uc eeao( n) uc) n
rtr fn( it{rtr x}
eun uc) n
eun
}
fn mi( {
uc an)
f: Gnrtr3
= eeao()
ftPitnf)
m.rnl(()
}
Run
50. Closures
Se pueden utilizar también para agrupar código, aunque no sea estrictamente
necesario, a veces queda más limpio.
adfxss: fn(ae prmsrn){
dIEit = ucnm, aa tig
vle o : ps[aa]
au, k = otprm
i o {
f k
mthnm]=bo.{$n:vle
ac[ae
snM`i` au}
}
}
adfxss`e` `e`
dIEit(sx, sx)
adfxss`sau` `sau`
dIEit(mtts, mtts)
adfxss`nlec_oe` `nlec`
dIEit(ifunezns, ifune)
adfxss`ye,`rpsltps)
dIEit(tp` pooa_ye`
adfxss`ai` `aeois)
dIEit(ctd, ctgre`
adfxss`oi` `omre`
dIEit(cmd, cmecs)
52. Defer
sau
tts
: htCin.tts)
= tpletSau(
rslJo : htCin.eut)
eutsn = tpletRsl(
i nl! htCin.ro( | 20! sau {
f i = tpletErr) | 0 = tts
htCin.ls(
tpletCoe)
rtr
eun
}
vrrsl [itrae}
a eut ]nefc{
i er: jo.nasa(eutsn &eut;nl! er{
f r = snUmrhlrslJo, rsl) i = r
htCin.ls(
tpletCoe)
rtr
eun
}
i !rsl[sces]{
f
eut`ucs`
htCin.ls(
tpletCoe)
rtr
eun
}
53. Defer
sau,rslJo,er: htCin.eut)
tts eutsn r = tpletRsl(
dfrhtCin.ls(
ee tpletCoe)
i nl! er| 20! sau {
f i = r | 0 = tts
rtr
eun
}
vrrsl [itrae}
a eut ]nefc{
i er: jo.nasa(eutsn &eut;nl! er{
f r = snUmrhlrslJo, rsl) i = r
rtr
eun
}
i !rsl[sces]{
f
eut`ucs`
rtr
eun
}
54. Concurrencia
Go provee de diversos mecanismos para manejar la concurrencia de forma
adecuada.
Sobre todo, haremos uso de go-routinas y canales.
La filosofía es "Share memory by communicating".
Es importante no confundir concurrencia con paralelismo.
Linux hasta la versión 2.0 no era paralelo, aunque si era concurrente.
El siguiente programa NO es paralelo, aunque sí concurrente.
fn mi( {
uc an)
c: mk(hnit
= aeca n)
g fn( {c< 1})
o uc)
(
g fn( {c< 2})
o uc)
(
x y: <c <c
,
= -, ftPitnx y
m.rnl(, )
}
Run
55. Un ejemplo real
fn (xc*aallxctr Ee( PrleFn){
uc ee PrleEeuo) xcf aalluc
c: mk(hnPrleRsos)
= aeca aallepne
cn,d : GtBon)
on b = eDCn(
g fn( {
o uc)
dfrfn( {
ee uc)
i r: rcvr) nl! r{
f
= eoe(; i =
er o : r(ro)
r, k = .err
i !k{
f o
er=ftErr(pg %" r
r
m.rof"k: v, )
}
c< PrleRsos{i,er
- aallepnenl r}
}
})
(
dfrcn.ls(
ee onCoe)
rsl,er: fd)
eut r = (b
c< PrleRsos{eut er
- aallepnersl, r}
})
(
ee.hnes=apn(xccanl,c
xccanl
pedee.hnes )
}
57. Entorno Go
run: Ejecutar un programa "sin compilarlo".
vet: Buscar "problemas", algo parecido a findbugs.
fix: Reescribir sentencias para utilizar APIs más "modernas", se utiliza al actualizar
Go a una nueva versión.
fmt: ¿Espacios o tabs? ¡Nunca más! Formatea con "go fmt".
pprof: ¿Donde pierde más tiempo mi programa? ¿Dónde consume más RAM?
doc: Generación automática de documentación.
test: Ejecutar los tests. También ejecuta benchmarks al pasarle el flag "-bench".
get: Descargar dependencias de un proyecto.
Flag "-race": Detector de condiciones de carrera, desde Go 1.1.
58. Deploy
En Go se recomienda colocar la URL en el import. De esta forma, "go get" puede
descargar automáticamente las dependencias y colocarlas en el $GOPATH.
ipr (
mot
lg`ihbcmchbseo`
o gtu.o/iu/elg
`ai.r/2mo
lbxogv/g`
)
Golang compila estáticamente las dependencias.
El resultado es un ELF (o .exe, o...) listo para ejecutar en cualquier máquina, sin
instalar nada más.
59. ¿Y esto se usa?
dl.google.com es un servidor Go.
Docker. Administrador de "containers" LXC.
Packer. Herramienta para crear imágenes de máquinas virtuales automáticamente.
Youtube. Liberó y utiliza Vitess, una herramienta Go para escalar MySQL.
10gen. El servicio de backups de MongoDB está escrito en GO.
Bitly. Han liberado NSQ, una plataforma de mensajería en tiempo real.
pool.ntp.org. Ya dispone de servidores hechos en Go.
Y muchos, muchos otros.
code.google.com/p/go-wiki/wiki/GoUsers(https://code.google.com/p/go-wiki/wiki/GoUsers)
60. Thank you
Antonio Nicolás Pina
Scalia
antonio@scalia.es (mailto:antonio@scalia.es)
http://scalia.es/ (http://scalia.es/)
@ANPez (http://twitter.com/ANPez)
@scalia_es (http://twitter.com/scalia_es)