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
|
---
name: Go
category: language
language: Go
filename: learngo-fi.go
contributors:
- ["Sonia Keys", "https://github.com/soniakeys"]
- ["Christopher Bess", "https://github.com/cbess"]
- ["Jesse Johnson", "https://github.com/holocronweaver"]
- ["Quint Guvernator", "https://github.com/qguv"]
- ["Jose Donizetti", "https://github.com/josedonizetti"]
- ["Alexej Friesen", "https://github.com/heyalexej"]
- ["Clayton Walker", "https://github.com/cwalk"]
translators:
- ["Timo Virkkunen", "https://github.com/ComSecNinja"]
lang: fi-fi
---
Go luotiin työn tekemistä varten. Se ei ole tietojenkäsittelyn uusin trendi,
mutta se on uusin nopein tapa ratkaista oikean maailman ongelmia.
Sillä on staattisesti tyypitetyistä imperatiivisista kielistä tuttuja
konsepteja. Se kääntyy ja suorittuu nopeasti, lisää helposti käsitettävän
samanaikaisten komentojen suorittamisen nykyaikaisten moniytimisten
prosessoreiden hyödyntämiseksi ja antaa käyttäjälle ominaisuuksia suurten
projektien käsittelemiseksi.
Go tuo mukanaan loistavan oletuskirjaston sekä innokkaan yhteisön.
```go
// Yhden rivin kommentti
/* Useamman
rivin kommentti */
// Package -lausekkeella aloitetaan jokainen lähdekooditiedosto.
// main on erityinen nimi joka ilmoittaa
// suoritettavan tiedoston kirjaston sijasta.
package main
// Import -lauseke ilmoittaa tässä tiedostossa käytetyt kirjastot.
import (
"fmt" // Paketti Go:n oletuskirjastosta.
"io/ioutil" // Implementoi hyödyllisiä I/O -funktioita.
m "math" // Matematiikkakirjasto jolla on paikallinen nimi m.
"net/http" // Kyllä, web-palvelin!
"strconv" // Kirjainjonojen muuntajia.
)
// Funktion määrittelijä. Main on erityinen: se on ohjelman suorittamisen
// aloittamisen alkupiste. Rakasta tai vihaa sitä, Go käyttää aaltosulkeita.
func main() {
// Println tulostaa rivin stdoutiin.
// Se tulee paketin fmt mukana, joten paketin nimi on mainittava.
fmt.Println("Hei maailma!")
// Kutsu toista funktiota tämän paketin sisällä.
beyondHello()
}
// Funktioilla voi olla parametrejä sulkeissa.
// Vaikkei parametrejä olisikaan, sulkeet ovat silti pakolliset.
func beyondHello() {
var x int // Muuttujan ilmoittaminen: ne täytyy ilmoittaa ennen käyttöä.
x = 3 // Arvon antaminen muuttujalle.
// "Lyhyet" ilmoitukset käyttävät := joka päättelee tyypin, ilmoittaa
// sekä antaa arvon muuttujalle.
y := 4
sum, prod := learnMultiple(x, y) // Funktio palauttaa kaksi arvoa.
fmt.Println("summa:", sum, "tulo:", prod) // Yksinkertainen tuloste.
learnTypes() // < y minuuttia, opi lisää!
}
/* <- usean rivin kommentti
Funktioilla voi olla parametrejä ja (useita!) palautusarvoja.
Tässä `x`, `y` ovat argumenttejä ja `sum`, `prod` ovat ne, mitä palautetaan.
Huomaa että `x` ja `sum` saavat tyyin `int`.
*/
func learnMultiple(x, y int) (sum, prod int) {
return x + y, x * y // Palauta kaksi arvoa.
}
// Sisäänrakennettuja tyyppejä ja todellisarvoja.
func learnTypes() {
// Lyhyt ilmoitus antaa yleensä haluamasi.
str := "Opi Go!" // merkkijonotyyppi.
s2 := `"raaka" todellisarvoinen merkkijono
voi sisältää rivinvaihtoja.` // Sama merkkijonotyyppi.
// Ei-ASCII todellisarvo. Go-lähdekoodi on UTF-8.
g := 'Σ' // riimutyyppi, lempinimi int32:lle, sisältää unicode-koodipisteen.
f := 3.14159 //float64, IEEE-754 64-bittinen liukuluku.
c := 3 + 4i // complex128, sisäisesti ilmaistu kahdella float64:lla.
// var -syntaksi alkuarvoilla.
var u uint = 7 // Etumerkitön, toteutus riippuvainen koosta kuten int.
var pi float32 = 22. / 7
// Muuntosyntaksi lyhyellä ilmoituksella.
n := byte('\n') // byte on leminimi uint8:lle.
// Listoilla on kiinteä koko kääntöhetkellä.
var a4 [4]int // 4 int:in lista, alkiot ovat alustettu nolliksi.
a3 := [...]int{3, 1, 5} // Listan alustaja jonka kiinteäksi kooksi tulee 3
// alkiota, jotka saavat arvot 3, 1, ja 5.
// Siivuilla on muuttuva koko. Sekä listoilla että siivuilla on puolensa,
// mutta siivut ovat yleisempiä käyttötapojensa vuoksi.
s3 := []int{4, 5, 9} // Vertaa a3: ei sananheittoa (...).
s4 := make([]int, 4) // Varaa 4 int:n siivun, alkiot alustettu nolliksi.
var d2 [][]float64 // Vain ilmoitus, muistia ei varata.
bs := []byte("a slice") // Tyypinmuuntosyntaksi.
// Koska siivut ovat dynaamisia, niitä voidaan yhdistellä sellaisinaan.
// Lisätäksesi alkioita siivuun, käytä sisäänrakennettua append()-funktiota.
// Ensimmäinen argumentti on siivu, johon alkoita lisätään.
s := []int{1, 2, 3} // Tuloksena on kolmen alkion pituinen lista.
s = append(s, 4, 5, 6) // Lisätty kolme alkiota. Siivun pituudeksi tulee 6.
fmt.Println(s) // Päivitetty siivu on nyt [1 2 3 4 5 6]
// Lisätäksesi siivun toiseen voit antaa append-funktiolle referenssin
// siivuun tai todellisarvoiseen siivuun lisäämällä sanaheiton argumentin
// perään. Tämä tapa purkaa siivun alkiot ja lisää ne siivuun s.
s = append(s, []int{7, 8, 9}...) // 2. argumentti on todellisarvoinen siivu.
fmt.Println(s) // Päivitetty siivu on nyt [1 2 3 4 5 6 7 8 9]
p, q := learnMemory() // Ilmoittaa p ja q olevan tyyppiä osoittaja int:iin.
fmt.Println(*p, *q) // * seuraa osoittajaa. Tämä tulostaa kaksi int:ä.
// Kartat ovat dynaamisesti kasvavia assosiatiivisia listoja, kuten hash tai
// dictionary toisissa kielissä.
m := map[string]int{"three": 3, "four": 4}
m["one"] = 1
// Käyttämättömät muuttujat ovat virheitä Go:ssa.
// Alaviiva antaa sinun "käyttää" muuttujan mutta hylätä sen arvon.
_, _, _, _, _, _, _, _, _, _ = str, s2, g, f, u, pi, n, a3, s4, bs
// Tulostaminen tietysti lasketaan muuttujan käyttämiseksi.
fmt.Println(s, c, a4, s3, d2, m)
learnFlowControl() // Takaisin flowiin.
}
// Go:ssa on useista muista kielistä poiketen mahdollista käyttää nimettyjä
// palautusarvoja.
// Nimen antaminen palautettavan arvon tyypille funktion ilmoitusrivillä
// mahdollistaa helpon palaamisen useasta eri funktion suorituskohdasta sekä
// pelkän return-lausekkeen käytön ilman muita mainintoja.
func learnNamedReturns(x, y int) (z int) {
z = x * y
return // z on epäsuorasti tässä, koska nimesimme sen aiemmin.
}
// Go kerää kaikki roskansa. Siinä on osoittajia mutta ei niiden laskentoa.
// Voit tehdä virheen mitättömällä osoittajalla, mutta et
// kasvattamalla osoittajaa.
func learnMemory() (p, q *int) {
// Nimetyillä palautusarvoilla p ja q on tyyppi osoittaja int:iin.
p = new(int) // Sisäänrakennettu funktio new varaa muistia.
// Varattu int on alustettu nollaksi, p ei ole enää mitätön.
s := make([]int, 20) // Varaa 20 int:ä yhteen kohtaan muistissa.
s[3] = 7 // Anna yhdelle niistä arvo.
r := -2 // Ilmoita toinen paikallinen muuttuja.
return &s[3], &r // & ottaa asian osoitteen muistissa.
}
func expensiveComputation() float64 {
return m.Exp(10)
}
func learnFlowControl() {
// If -lausekkeet vaativat aaltosulkeet mutta ei tavallisia sulkeita.
if true {
fmt.Println("mitä mä sanoin")
}
// Muotoilu on standardoitu käyttämällä komentorivin komentoa "go fmt".
if false {
// Nyrpistys.
} else {
// Nautinto.
}
// Käytä switch -lauseketta ketjutettujen if -lausekkeiden sijasta.
x := 42.0
switch x {
case 0:
case 1:
case 42:
// Tapaukset eivät "tipu läpi".
/*
Kuitenkin meillä on erikseen `fallthrough` -avainsana. Katso:
https://github.com/golang/go/wiki/Switch#fall-through
*/
case 43:
// Saavuttamaton.
default:
// Oletustapaus (default) on valinnainen.
}
// Kuten if, for -lauseke ei myöskään käytä tavallisia sulkeita.
// for- ja if- lausekkeissa ilmoitetut muuttujat ovat paikallisia niiden
// piireissä.
for x := 0; x < 3; x++ { // ++ on lauseke. Sama kuin "x = x + 1".
fmt.Println("iteraatio", x)
}
// x == 42 tässä.
// For on kielen ainoa silmukkalauseke mutta sillä on vaihtoehtosia muotoja.
for { // Päättymätön silmukka.
break // Kunhan vitsailin.
continue // Saavuttamaton.
}
// Voit käyttää range -lauseketta iteroidaksesi listojen, siivujen, merkki-
// jonojen, karttojen tai kanavien läpi. range palauttaa yhden (kanava) tai
// kaksi arvoa (lista, siivu, merkkijono ja kartta).
for key, value := range map[string]int{"yksi": 1, "kaksi": 2, "kolme": 3} {
// jokaista kartan paria kohden, tulosta avain ja arvo
fmt.Printf("avain=%s, arvo=%d\n", key, value)
}
// Kuten for -lausekkeessa := if -lausekkeessa tarkoittaa ilmoittamista ja
// arvon asettamista.
// Aseta ensin y, sitten testaa onko y > x.
if y := expensiveComputation(); y > x {
x = y
}
// Todellisarvoiset funktiot ovat sulkeumia.
xBig := func() bool {
return x > 10000 // Viittaa ylempänä ilmoitettuun x:ään.
}
fmt.Println("xBig:", xBig()) // tosi (viimeisin arvo on e^10).
x = 1.3e3 // Tämä tekee x == 1300
fmt.Println("xBig:", xBig()) // epätosi nyt.
// Lisäksi todellisarvoiset funktiot voidaan samalla sekä ilmoittaa että
// kutsua, jolloin niitä voidaan käyttää funtioiden argumentteina kunhan:
// a) todellisarvoinen funktio kutsutaan välittömästi (),
// b) palautettu tyyppi vastaa odotettua argumentin tyyppiä.
fmt.Println("Lisää ja tuplaa kaksi numeroa: ",
func(a, b int) int {
return (a + b) * 2
}(10, 2)) // Kutsuttu argumenteilla 10 ja 2
// => Lisää ja tuplaa kaksi numeroa: 24
// Kun tarvitset sitä, rakastat sitä.
goto love
love:
learnFunctionFactory() // Funktioita palauttavat funktiot
learnDefer() // Nopea kiertoreitti tärkeään avainsanaan.
learnInterfaces() // Hyvää kamaa tulossa!
}
func learnFunctionFactory() {
// Seuraavat kaksi ovat vastaavia, mutta toinen on käytännöllisempi
fmt.Println(sentenceFactory("kesä")("Kaunis", "päivä!"))
d := sentenceFactory("kesä")
fmt.Println(d("Kaunis", "päivä!"))
fmt.Println(d("Laiska", "iltapäivä!"))
}
// Somisteet ovat yleisiä toisissa kielissä. Sama saavutetaan Go:ssa käyttämällä
// todellisarvoisia funktioita jotka ottavat vastaan argumentteja.
func sentenceFactory(mystring string) func(before, after string) string {
return func(before, after string) string {
return fmt.Sprintf("%s %s %s", before, mystring, after) // uusi jono
}
}
func learnDefer() (ok bool) {
// Lykätyt lausekkeet suoritetaan juuri ennen funktiosta palaamista.
defer fmt.Println("lykätyt lausekkeet suorittuvat")
defer fmt.Println("käänteisessä järjestyksessä (LIFO).")
defer fmt.Println("\nTämä rivi tulostuu ensin, koska")
// Defer -lauseketta käytetään yleisesti tiedoston sulkemiseksi, jotta
// tiedoston sulkeva funktio pysyy lähellä sen avannutta funktiota.
return true
}
// Määrittele Stringer rajapintatyypiksi jolla on
// yksi jäsenfunktio eli metodi, String.
type Stringer interface {
String() string
}
// Määrittele pair rakenteeksi jossa on kaksi kenttää, x ja y tyyppiä int.
type pair struct {
x, y int
}
// Määrittele jäsenfunktio pair:lle. Pair tyydyttää nyt Stringer -rajapinnan.
func (p pair) String() string { // p:tä kutsutaan nimellä "receiver"
// Sprintf on toinen julkinen funktio paketissa fmt.
// Pistesyntaksilla viitataan P:n kenttiin.
return fmt.Sprintf("(%d, %d)", p.x, p.y)
}
func learnInterfaces() {
// Aaltosuljesyntaksi on "todellisarvoinen rakenne". Se todentuu alustetuksi
// rakenteeksi. := -syntaksi ilmoittaa ja alustaa p:n täksi rakenteeksi.
p := pair{3, 4}
fmt.Println(p.String()) // Kutsu p:n (tyyppiä pair) jäsenfunktiota String.
var i Stringer // Ilmoita i Stringer-rajapintatyypiksi.
i = p // Pätevä koska pair tyydyttää rajapinnan Stringer.
// Kutsu i:n (Stringer) jäsenfunktiota String. Tuloste on sama kuin yllä.
fmt.Println(i.String())
// Funktiot fmt-paketissa kutsuvat argumenttien String-jäsenfunktiota
// selvittääkseen onko niistä saatavilla tulostettavaa vastinetta.
fmt.Println(p) // Tuloste on sama kuin yllä. Println kutsuu String-metodia.
fmt.Println(i) // Tuloste on sama kuin yllä.
learnVariadicParams("loistavaa", "oppimista", "täällä!")
}
// Funktioilla voi olla muuttuva eli variteettinen
// määrä argumentteja eli parametrejä.
func learnVariadicParams(myStrings ...interface{}) {
// Iteroi jokaisen argumentin läpi.
// Tässä alaviivalla sivuutetaan argumenttilistan kunkin kohdan indeksi.
for _, param := range myStrings {
fmt.Println("param:", param)
}
// Luovuta variteettinen arvo variteettisena parametrinä.
fmt.Println("params:", fmt.Sprintln(myStrings...))
learnErrorHandling()
}
func learnErrorHandling() {
// "; ok" -muotoa käytetään selvittääksemme toimiko jokin vai ei.
m := map[int]string{3: "kolme", 4: "neljä"}
if x, ok := m[1]; !ok { // ok on epätosi koska 1 ei ole kartassa.
fmt.Println("ei ketään täällä")
} else {
fmt.Print(x) // x olisi arvo jos se olisi kartassa.
}
// Virhearvo voi kertoa muutakin ongelmasta.
if _, err := strconv.Atoi("ei-luku"); err != nil { // _ sivuuttaa arvon
// tulostaa strconv.ParseInt: parsing "ei-luku": invalid syntax
fmt.Println(err)
}
// Palaamme rajapintoihin hieman myöhemmin. Sillä välin,
learnConcurrency()
}
// c on kanava, samanaikaisturvallinen viestintäolio.
func inc(i int, c chan int) {
c <- i + 1 // <- on "lähetysoperaattori" kun kanava on siitä vasemmalla.
}
// Käytämme inc -funktiota samanaikaiseen lukujen lisäämiseen.
func learnConcurrency() {
// Sama make -funktio jota käytimme aikaisemmin siivun luomiseksi. Make
// varaa muistin ja alustaa siivut, kartat ja kanavat.
c := make(chan int)
// Aloita kolme samanaikaista gorutiinia (goroutine). Luvut kasvavat
// samanaikaisesti ja ehkäpä rinnakkain jos laite on kykenevä ja oikein
// määritelty. Kaikki kolme lähettävät samalle kanavalle.
go inc(0, c) // go -lauseke aloittaa uuden gorutiinin.
go inc(10, c)
go inc(-805, c)
// Lue kolme palautusarvoa kanavalta ja tulosta ne.
// Niiden saapumisjärjestystä ei voida taata!
// <- on "vastaanotto-operaattori" jos kanava on oikealla
fmt.Println(<-c, <-c, <-c)
cs := make(chan string) // Toinen kanava joka käsittelee merkkijonoja.
ccs := make(chan chan string) // Kanava joka käsittelee merkkijonokanavia.
go func() { c <- 84 }() // Aloita uusi gorutiini arvon lähettämiseksi.
go func() { cs <- "sanaa" }() // Uudestaan, mutta cs -kanava tällä kertaa.
// Select -lausekkeella on syntaksi kuten switch -lausekkeella mutta
// jokainen tapaus sisältää kanavaoperaation. Se valitsee satunnaisen
// tapauksen niistä kanavista, jotka ovat kommunikaatiovalmiita
select {
case i := <-c: // Vastaanotettu arvo voidaan antaa muuttujalle
fmt.Printf("se on %T", i)
case <-cs: // tai vastaanotettu arvo voidaan sivuuttaa.
fmt.Println("se on merkkijono")
case <-ccs: // Tyhjä kanava; ei valmis kommunikaatioon.
fmt.Println("ei tapahtunut.")
}
// Tässä vaiheessa arvo oli otettu joko c:ltä tai cs:ltä. Yksi kahdesta
// ylempänä aloitetusta gorutiinista on valmistunut, toinen pysyy tukossa.
learnWebProgramming() // Go tekee sitä. Sinäkin haluat tehdä sitä.
}
// Yksittäinen funktio http -paketista aloittaa web-palvelimen.
func learnWebProgramming() {
// ListenAndServe:n ensimmäinen parametri on TCP-osoite, jota kuunnellaan.
// Toinen parametri on rajapinta, http.Handler.
go func() {
err := http.ListenAndServe(":8080", pair{})
fmt.Println(err) // älä sivuuta virheitä.
}()
requestServer()
}
// Tee pair:sta http.Handler implementoimalla sen ainoa metodi, ServeHTTP.
func (p pair) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// Tarjoa dataa metodilla http.ResponseWriter.
w.Write([]byte("Opit Go:n Y minuutissa!"))
}
func requestServer() {
resp, err := http.Get("http://localhost:8080")
fmt.Println(err)
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
fmt.Printf("\nWeb-palvelin sanoo: `%s`", string(body))
}
```
## Lisää luettavaa
Go-tietämyksen alku ja juuri on sen [virallinen verkkosivu](https://go.dev/).
Siellä voit seurata oppitunteja, askarrella vuorovaikutteisesti sekä lukea paljon.
Kierroksen lisäksi [dokumentaatio](https://go.dev/doc/) pitää sisällään tietoa
siistin Go-koodin kirjoittamisesta, pakettien ja komentojen käytöstä sekä julkaisuhistoriasta.
Kielen määritelmä itsessään on suuresti suositeltavissa. Se on helppolukuinen ja
yllättävän lyhyt (niissä määrin kuin kielimääritelmät nykypäivänä ovat.)
Voit askarrella parissa kanssa [Go playgroundissa](https://go.dev/play/p/tnWMjr16Mm).
Muuttele sitä ja aja se selaimestasi! Huomaa, että voit käyttää [https://go.dev/play/](https://go.dev/play/)
[REPL:na](https://en.wikipedia.org/wiki/Read-eval-print_loop) testataksesi ja koodataksesi selaimessasi, ilman Go:n asentamista.
Go:n opiskelijoiden lukulistalla on [oletuskirjaston lähdekoodi](https://go.dev/src/).
Kattavasti dokumentoituna se antaa parhaan kuvan helppolukuisesta ja ymmärrettävästä Go-koodista,
-tyylistä ja -tavoista. Voit klikata funktion nimeä [doukumentaatiossa](https://go.dev/pkg/) ja
lähdekoodi tulee esille!
Toinen loistava paikka oppia on [Go by example](https://gobyexample.com/).
Go Mobile lisää tuen mobiilialustoille (Android ja iOS). Voit kirjoittaa pelkällä Go:lla natiiveja applikaatioita tai tehdä kirjaston joka sisältää sidoksia
Go-paketista, jotka puolestaan voidaan kutsua Javasta (Android) ja Objective-C:stä (iOS). Katso [lisätietoja](https://go.dev/wiki/Mobile).
|