-
Notifications
You must be signed in to change notification settings - Fork 0
/
tour.article
854 lines (467 loc) · 25.6 KB
/
tour.article
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
Tur Go
The Go Authors
http://golang.org
# Throughout this file are a series of lines that begin with
# the string "#appengine: ". These lines are included in
# the tour content when deployed as an App Engine app.
# Furthermore, a single non-blank line that immediately follows
# a run of "#appengine: " lines will be hidden. This is so that
# App Engine-specific content may replace existing content.
# For example, this paragraph
# We are running
# #appengine: on App Engine.
# locally.
# Yay!
# reads as "We are running on App Engine. Yay!" on App Engine,
# and "We are running locally. Yay!" otherwise.
* Hello, 世界
Selamat datang di tur [[http://golang.org][bahasa pemrograman Go]].
Tur dibagi menjadi tiga bagian: konsep dasar, _method_ dan _interfaces_, dan _concurrency_.
Melalui tur Anda akan menemukan serangkaian latihan untuk diselesaikan.
Tur bersifat interaktif. Klik pada tombol Jalankan (atau tekan Shift-Enter) untuk mengkompil program di
#appengine: _remote_ _server_.
komputer Anda.
Hasilnya ditampilkan dibawah kode.
Program contoh ini mendemonstrasikan beberapa aspek dari Go. Program di tur ditujukan sebagai langkah awal percobaan Anda.
Sunting program dan jalankan kembali.
Jika Anda sudah siap ke tahap selanjutnya, klik pada tombol Berikutnya atau tekan PageDown.
.play prog/hello.go
* Go lokal
Tur juga tersedia dalam bahasa lain:
- [[http://go-tour-br.appspot.com/][Brazilian Portuguese — Português do Brasil]]
- [[http://go-tour-ca.appspot.com/][Catalan — Català]]
- [[http://go-tour-es.appspot.com/][Spanish — Español]]
- [[http://go-tour-fr.appspot.com/][French - Français]]
- [[http://go-tour-he.appspot.com/][Hebrew — עִבְרִית]]
- [[http://go-tour-jp.appspot.com/][Japanese — 日本語]]
- [[http://go-tour-ro.appspot.com/][Romanian - Română]]
- [[http://go-tour-zh.appspot.com/][Chinese — 普通话]]
- [[http://go-tour-id.appspot.com/][Indonesia — Bahasa Indonesia]]
Klik pada tombol "berikut" atau tekan PageDown untuk melanjutkan.
* Paket
Setiap program Go tersusun dari paket.
Program mulai berjalan di paket `main`.
Program ini menggunakan paket dengan dengan import path `"fmt"` dan `"math"`.
Berdasarkan konvensi, nama paket sama dengan element terakhir dari import path.
.play prog/packages.go
* Import
Kode ini mengelompokan import dengan pernyataan import kurung buka-tutup. Anda juga bisa menulis beberapa pernyataan import menjadi beberapa baris, seperti:
import "fmt"
import "math"
.play prog/imports.go
* Nama yang diekspor
Setelah mengimport sebuah paket, Anda dapat menggunakan nama yang diekspor.
Dalam Go, nama diekspor jika diawali dengan huruf kapital.
`Foo` merupakan nama yang diekspor, begitu juga `FOO`. Nama `foo` tidak diekspor.
Jalankan kode. Lalu rubah nama `math.pi` menjadi `math.Pi` dan coba lagi.
.play prog/exported-names.go
* Fungsi
Sebuah fungsi dapat menerima nol atau lebih argumen.
Pada contoh ini, `add` menerima dua parameter dengan tipe `int`.
Perhatikan bahwa tipe disebutkan _setelah_ nama variabel.
(Untuk penjelasan mengenai kenapa tipe terlihat seperti itu, lihat [[http://golang.org/doc/articles/gos_declaration_syntax.html][artikel mengenai deklarasi sintaks Go]].)
.play prog/functions.go
* Fungsi lanjutan
Ketika dua atau lebih konsekutif paramater fungsi memliki tipe sejenis, Anda dapat mengabaikan tipenya kecuali yang terakhir.
Pada contoh ini, kita menyingkat
x int, y int
menjadi
x, y int
.play prog/functions-continued.go
* Beberapa nilai balik
Sebuah fungsi dapat memberikan lebih dari satu nilai balik.
Fungsi ini memberikan nilai balik dua `string`.
.play prog/multiple-results.go
* Nilai balik bernama
Fungsi mengambil parameter. Dalam Go, fungsi dapat memberikan beberapa "nilai balik parameter", tidak hanya sebuah nilai. Nilai balik dapat bernama dan memiliki perilaku seperti variabel.
Jika parameter nilai balik bernama, sebuah pernyataan `return` tanpa argumen akan mengembalikan nilai saat itu dari parameter nilai balik.
.play prog/named-results.go
* Variabel
Pernyataan `var` mendeklarasikan sekumpulan variabel; seperti deretan argumen fungsi, tipe disebutkan terakhir.
.play prog/variables.go
* Variabel dengan nilai inisial
Deklarasi var dapat menyertakan nilai inisial, satu per variabel.
Jika terdapat nilai inisial, penyebutan tipe dapat diabaikan; variabel akan mengambil tipe dari nilai inisial.
.play prog/variables-with-initializers.go
* Deklarasi singkat variabel
Di dalam fungsi, pernyataan singkat pemberian nilai `:=` dapat digunakan menggantikan deklarasi `var` dengan tipe disertakan secara implisit.
(Setiap konstruk yang diawali dengan kata kunci dan konstruk `:=` tidak tersedia di luar fungsi.)
.play prog/short-variable-declarations.go
* Tipe dasar
Tipe dasar di Go antar lain
bool
string
int int8 int16 int32 int64
uint uint8 uint16 uint32 uint64 uintptr
byte // alias untuk uint8
rune // alias untuk int32
// merepresentasikan kode point Unicode
float32 float64
complex64 complex128
.play prog/basic-types.go
* Konstanta
Konstanta dideklarasikan seperti variabel, tapi dengan kata kunci `const`.
Konstanta dapat berupa karakter, string, boolean, atau nilai numerik.
.play prog/constants.go
* Konstanta Numerik
Konstanta numerik memiliki _nilai_ dengan presisi tinggi.
Konstanta tak bertipe menggunakan tipe yang dibutuhkan berdasarkan konteksnya.
Coba cetak juga `needInt(Big)`.
.play prog/numeric-constants.go
* For
Go hanya memiliki satu konstruk iterasi, yaitu iterasi `for`.
Bentuk iterasi `for` dasar terlihat seperti halnya iterasi di C atau Java, tapi tanpa kurung-buka-tutup `(`)` (tidak bersifat opsional, tapi benar-benar ditiadakan) dan kurawal-buka-tutup `{`}` tetap dibutuhkan.
.play prog/for.go
* For lanjutan
Sebagaimana di C atau Java, Anda dapat membiarkan pernyataan awal dan akhir kosong.
.play prog/for-continued.go
* For merupakan "while"-nya Go
Pada kondisi itu Anda dapat membuang titk-koma: `while` di C dibaca `for` dalam Go.
.play prog/for-is-gos-while.go
* Selamanya
Jika kondisi iterasi diabaikan maka akan beriterasi selamanya, jadi iterasi tanpa batas diekspresikan secara solid.
.play prog/forever.go
* If
Pernyataan `if` terlihat seperti halnya di C atau Java, tapi tanpa `(`)` dan `{`}` tetap dibutuhkan.
(Terdengar akrab?)
.play prog/if.go
* If dengan pernyataan singkat
Seperti `for`, pernyataan `if` dapat diawali dengan pernyataan singkat untuk dieksekusi sebelum evaluasi kondisi.
Variabel yang dideklarasikan dengan pernyataan singkat hanya bercakup sampai akhir `if`.
(Coba gunakan `v` di pernyataan `return` terkahir.)
.play prog/if-with-a-short-statement.go
* If dan else
Variabel dideklarasikan di dalam pernyataan singkat `if` juga tersedia di blok `else` manapun.
.play prog/if-and-else.go
* Latihan: Iterasi dan Fungsi
Sebagai cara untuk bermain dengan fungsi dan iterasi, implementasikan fungsi akar kuadrat dengan metode Newton.
Dalam kasus ini, metode Newton digunakan untuk mentaksir nilai `Sqrt(x)` dengan memilih nilai awal _z_ lalu mengulang:
.image static/newton.png
Untuk memulainya, ulangi kalkulasi sebanyak 10 kali dan lihat seberapa dekat jawabannya untuk beragam nilai (1, 2, 3, ...).
Selanjutnya, ganti kondisi iterasi untuk berhenti ketika nilai berhenti berganti (atau hanya berganti dengan delta yang sangat kecil). Perhatikan apakah iterasi terjadi lebih sedikit atau lebih banyak. Seberapa dekat hasil mu dengan [[http://golang.org/pkg/math/#Sqrt][math.Sqrt]]?
Petunjuk: untuk mendeklarasikan dan menginisialisasi nilai floating point, berikan sintaks floating point atau gunakan konversi:
z := float64(1)
z := 1.0
.play prog/exercise-loops-and-functions.go
* Struct
`struct` adalah kumpulan field.
(Dan deklarasi `type` melakukan apa yang Anda harapkan.)
.play prog/structs.go
* Field Struct
Field struct diakses menggunakan titik.
.play prog/struct-fields.go
* Pointer
Go memiliki pointer, tapi tidak ada pointer arimetik.
Field struct dapat diakses melalui pointer struct. Indireksi terhadap pointer bersifat transparan.
.play prog/pointers.go
* Literal Struct
Literal struct menandakan alokasi nilai struct baru dengan menjabarkan nilai field-nya.
Anda dapat menjabarkan sebagian field dengan menggunkan sintaks `Name:`. (Dan urutan nama field tidak berpengaruh.)
Prefix khusus `&` membuatkan pointer untuk struct yang baru dialokasikan.
.play prog/struct-literals.go
* Fungsi new
Expresi `new(T)` akan mengalokasikan nilai-kosong pada `T` dan mengembalikan pointer terhadapnya.
var t *T = new(T)
atau
t := new(T)
.play prog/the-new-function.go
# TODO(campoy): Arrays section
* Slice
Slice merujuk ke array sebuah nilai yang juga menyertakan panjang.
`[]T` merupakan slice dengan elemen bertipe `T`.
.play prog/slices.go
* Melakukan reslice pada slices
Slice dapat di- _reslice_, menciptakan sebuah nilai slice baru yang merujuk array yang sama.
Ekspresi
s[lo:hi]
menghasilkan slice dengan element dari `lo` sampai `hi-1`, inklusif. Sehinnga
s[lo:lo]
akan kosong dan
s[lo:lo+1]
memiliki satu elemen.
.play prog/slicing-slices.go
* Membuat slice
Slice dibuat dengan fungsi `make`. Yang berfungsi mengalokasikan array kosong dan mengembalikan slice yang merujuk ke array tersebut:
a := make([]int, 5) // len(a)=5
Untuk memberikan kapasitas, sebutkan di argument ketiga dari `make`:
b := make([]int, 0, 5) // len(b)=0, cap(b)=5
b = b[:cap(b)] // len(b)=5, cap(b)=5
b = b[1:] // len(b)=4, cap(b)=4
.play prog/making-slices.go
* Slice nil
Nilai kosong dari sabuah slice adalah `nil`.
Slice nil memiliki panjang dan kapasitas 0.
(Untuk belajar slice lebih lanjut, baca artikel [[http://golang.org/doc/articles/slices_usage_and_internals.html][Slice: penggunaan dan internalnya]].)
.play prog/nil-slices.go
# TODO(campoy): Appending to slices section
* Range
Bentuk `range` loop `for` akan mengiterasi elemen di slice atau map.
.play prog/range.go
* Range lanjutan
Anda dapat menghiraukan indeks atau nilai dengan memberikannya ke `_`.
Jika Anda hanya ingin indeks, buang ", value".
.play prog/range-continued.go
* Latihan: Slice
Implementasikan `Pic`. Berikan nilai balik slice dengan panjang `dy`, setiap elemennya juga slice `dx`, integer 8-bit tak bertanda. Saat Anda menjalankan program, akan tampil gambar interpretasi integer sebagai grayscale (bluescale sih sebenarnya).
Pilihan gambar terserah Anda. Fungsi yang menarik meliputi `x^y`, `(x+y)/2`, dan `x*y`.
(Anda membutuhkan sebuah loop untuk mengalokasikan setiap `[]uint8` didalam `[][]uint8`,)
(Gunakan `uint(intValue)` untuk mengkonvesi tipe.)
.play prog/exercise-slices.go
* Map
Map memetakan kunci dengan nilai.
Map harus dibuat dengan `make` (bukan `new`) sebelum digunakan; map `nil` tidak ada isinya dan tidak dapat diberikan nilai.
.play prog/maps.go
* Literal map
Literal map serupa dengan literal struct, tapi kunci dibutuhkan di literal map.
.play prog/map-literals.go
* Literal map lanjutan
Jika tipe teratas adalah nama tipe, Anda dapat mengabaikan penyebutan nama tipe dari literal elemen.
.play prog/map-literals-continued.go
* Memodifikasi Maps
Menambahkan atau meng- _update_ elemen di map `m`:
m[key] = elem
Memperoleh elemen:
elem = m[key]
Menghapus elemen:
delete(m, key)
Menguji apakah sebuah kunci tersedia dengan operasi penugasan dua-nilai:
elem, ok = m[key]
Jika `key` terdapat di `m`, `ok` bernilai `true`. Jika tidak, `ok` bernilai `false` dan `elem` mengandung nilai nol dari tipe elemen map.
Demikian juga saat membaca dari map, jika kunci tidak ada maka hasilnya adalah nilai nol dari tipe elemen map.
.play prog/mutating-maps.go
# TODO(campoy): Range on maps section
* Latihan: Map
Implementasikan `WordCount`. Fungsi ini harus memberikan nilai balik map jumlah "kata" di string `s`. Fungsi `wc.Test` menjalankan kumpulan tes terhadap fungsi yang diberikan dan mencetak sukses atau gagal.
Mungkin [[http://golang.org/pkg/strings/#Fields][strings.Fields]] dapat membantu Anda.
.play prog/exercise-maps.go
* Fungsi sebagai nilai
Fungsi juga merupakan nilai.
.play prog/function-values.go
* Fungsi closure
Dan fungsi juga sepenuhnya closure.
Fungsi `adder` memberikan nilai balik sebuah closure. Setiap closure terikat dengan variabel `sum` nya sendiri.
.play prog/function-closures.go
* Latihan: Fibonacci closure
Mari kita bermain dengan fungsi.
Implementasikan fungsi `fibonacci` yang mengembalikan nilai balik fungsi (closure) yang memberikan deret fibonacci.
.play prog/exercise-fibonacci-closure.go
* Switch
Mungkin Anda sudah mengetahui bagaimana `switch` akan terlihat.
Badan dari case akan break secara otomatis, kecuali diakhiri dengan pernyataan `fallthrough`.
.play prog/switch.go
* Urutan evaluasi switch
Case pada switch mengevaluasi case dari atas ke bawah, berhenti jika sebuah case berhasil terevaluasi.
(Misal,
switch i {
case 0:
case f():
}
tidak akan memanggil `f` jika `i==0`.)
#appengine: *Note:* Time di Go playground selalu ditampilkan dengan waktu mulai
#appengine: 2009-11-10 23:00:00 UTC, nilai yang maknanya diserahkan kepada Anda
#appengine: sebagai latihan.
.play prog/switch-evaluation-order.go
* Switch tanpa kondisi
Switch tanpa kondisi sama saja dengan `switch`true`.
Bentuk ini dapat menjadi cara rapih menulis rantai if-then-else yang panjang.
.play prog/switch-with-no-condition.go
* Advanced Exercise: Complex cube roots
* Latihan Tingkat Lanjut: Akar kubus kompleks
Mari telesuri dukungan bawaan Go untuk bilangan kompleks melalui tipe `complex64` dan `complex128`. Untuk akar kubus, metode Newton yang digunakan dalam perulangan:
.image static/newton3.png
Cari akar kubus dari 2 untuk memastikan algoritmanya bekerja. Ada fungsi [[http://golang.org/pkg/math/cmplx/#Pow][Pow]] di paket `math/cmplx`.
.play prog/advanced-exercise-complex-cube-roots.go
* Method dan Interface
Go tidak memiliki class. Tapi method dapat didefinisikan di tipe struct.
_Method_receiver_ tampil dengan argument sendiri diantara kata kunci `func` dan nama method.
.play prog/methods.go
* Method lanjutan
Bahkan Anda dapat mendefinisikan method di tipe apapun yang Anda definisikan di paket, tidak hanya struct.
Anda tidak dapat mendefinisikan method di tipe dari paket lain, atau di tipe dasar.
.play prog/methods-continued.go
* Method dengan receiver pointer
Method dapat diasosiasikan dengan nama tipe atau pointer ke nama tipe.
Kita baru saja melihat method `Abs`. Satu dengan tipe pointer `*Vertex` dan satu lagi dengan tipe `MyFloat`.
Ada dua alasan menggunakan receiver pointer. Pertama, untuk menghindari salinan nilai satiap kali method dipanggil (sangat efisien jika nilai tipe merupakan struct yang besar). Kedua, agar method dapat memodifikasi nilai yang receiver rujuk.
Coba ubah deklarasi method `Abs` dan `Scale` dengan menggunakan `Vertex` sebagai receiver.
Method `Scale` tidak berpengaruh saat `v` merupakan `Vertex`. `Scale` memodifikasi `v`. Saat `v` merupakan nilai tipe (non-pointer), method melihatnya sebagai salinan `Vertex` dan tidak dapat memodifikasi nilai orisinil.
`Abs` dapat berjalan dengan keduanya karena hanya membaca `v`. Tidak masalah apakah yang dibaca itu nilai orisinil (melalui pointer) atau salinan nilai-nya.
.play prog/methods-with-pointer-receivers.go
* Interfaces
An interface type is defined by a set of methods.
A value of interface type can hold any value that implements those methods.
.play prog/interfaces.go
* Interfaces are satisfied implicitly
A type implements an interface by implementing the methods.
_There_is_no_explicit_declaration_of_intent._
Implicit interfaces decouple implementation packages from the packages that define the interfaces: neither depends on the other.
It also encourages the definition of precise interfaces, because you don't have to find every implementation and tag it with the new interface name.
[[http://golang.org/pkg/io/][Package io]] defines `Reader` and `Writer`; you don't have to.
.play prog/interfaces-are-satisfied-implicitly.go
* Errors
An error is anything that can describe itself as an error string. The idea is captured by the predefined, built-in interface type, `error`, with its single method, `Error`, returning a string:
type error interface {
Error() string
}
The `fmt` package's various print routines automatically know to call the method when asked to print an `error`.
.play prog/errors.go
* Exercise: Errors
Copy your `Sqrt` function from the earlier exercises and modify it to return an `error` value.
`Sqrt` should return a non-nil error value when given a negative number, as it doesn't support complex numbers.
Create a new type
type ErrNegativeSqrt float64
and make it an `error` by giving it a
func (e ErrNegativeSqrt) Error() string
method such that `ErrNegativeSqrt(-2).Error()` returns `"cannot`Sqrt`negative`number:`-2"`.
*Note:* a call to `fmt.Print(e)` inside the `Error` method will send the program into an infinite loop. You can avoid this by converting `e` first: `fmt.Print(float64(e))`. Why?
Change your `Sqrt` function to return an `ErrNegativeSqrt` value when given a negative number.
.play prog/exercise-errors.go
* Web servers
[[http://golang.org/pkg/net/http/][Package http]] serves HTTP requests using any value that implements `http.Handler`:
package http
type Handler interface {
ServeHTTP(w ResponseWriter, r *Request)
}
In this example, the type `Hello` implements `http.Handler`.
Visit [[http://localhost:4000/][http://localhost:4000/]] to see the greeting.
#appengine: *Note:* This example won't run through the web-based tour user
#appengine: interface. To try writing web servers you may want to
#appengine: [[http://golang.org/doc/install/][Install Go]].
.play prog/web-servers.go
* Exercise: HTTP Handlers
Implement the following types and define ServeHTTP methods on them. Register them to handle specific paths in your web server.
type String string
type Struct struct {
Greeting string
Punct string
Who string
}
For example, you should be able to register handlers using:
http.Handle("/string", String("I'm a frayed knot."))
http.Handle("/struct", &Struct{"Hello", ":", "Gophers!"})
.play prog/exercise-http-handlers.go
* Images
[[http://golang.org/pkg/image/#Image][Package image]] defines the `Image` interface:
package image
type Image interface {
ColorModel() color.Model
Bounds() Rectangle
At(x, y int) color.Color
}
(See [[http://golang.org/pkg/image/#Image][the documentation]] for all the details.)
Also, `color.Color` and `color.Model` are interfaces, but we'll ignore that by using the predefined implementations `color.RGBA` and `color.RGBAModel`.
.play prog/images.go
* Exercise: Images
Remember the picture generator you wrote earlier? Let's write another one, but this time it will return an implementation of `image.Image` instead of a slice of data.
Define your own `Image` type, implement [[http://golang.org/pkg/image/#Image][the necessary methods]], and call `pic.ShowImage`.
`Bounds` should return a `image.Rectangle`, like `image.Rect(0,`0,`w,`h)`.
`ColorModel` should return `color.RGBAModel`.
`At` should return a color; the value `v` in the last picture generator corresponds to `color.RGBA{v,`v,`255,`255}` in this one.
.play prog/exercise-images.go
* Exercise: Rot13 Reader
A common pattern is an [[http://golang.org/pkg/io/#Reader][io.Reader]] that wraps another `io.Reader`, modifying the stream in some way.
For example, the [[http://golang.org/pkg/compress/gzip/#NewReader][gzip.NewReader]] function takes an `io.Reader` (a stream of gzipped data) and returns a `*gzip.Reader` that also implements `io.Reader` (a stream of the decompressed data).
Implement a `rot13Reader` that implements `io.Reader` and reads from an `io.Reader`, modifying the stream by applying the [[http://en.wikipedia.org/wiki/ROT13][ROT13]] substitution cipher to all alphabetical characters.
The `rot13Reader` type is provided for you. Make it an `io.Reader` by implementing its `Read` method.
.play prog/exercise-rot-reader.go
* Concurrency
* Goroutines
A _goroutine_ is a lightweight thread managed by the Go runtime.
go f(x, y, z)
starts a new goroutine running
f(x, y, z)
The evaluation of `f`, `x`, `y`, and `z` happens in the current goroutine and the execution of `f` happens in the new goroutine.
Goroutines run in the same address space, so access to shared memory must be synchronized. The [[http://golang.org/pkg/sync/][`sync`]] package provides useful primitives, although you won't need them much in Go as there are other primitives. (See the next slide.)
.play prog/goroutines.go
* Channels
Channels are a typed conduit through which you can send and receive values with the channel operator, `<-`.
ch <- v // Send v to channel ch.
v := <-ch // Receive from ch, and
// assign value to v.
(The data flows in the direction of the arrow.)
Like maps and slices, channels must be created before use:
ch := make(chan int)
By default, sends and receives block until the other side is ready. This allows goroutines to synchronize without explicit locks or condition variables.
.play prog/channels.go
* Buffered Channels
Channels can be _buffered_. Provide the buffer length as the second argument to `make` to initialize a buffered channel:
ch := make(chan int, 100)
Sends to a buffered channel block only when the buffer is full. Receives block when the buffer is empty.
Modify the example to overfill the buffer and see what happens.
.play prog/buffered-channels.go
* Range and Close
A sender can `close` a channel to indicate that no more values will be sent. Receivers can test whether a channel has been closed by assigning a second parameter to the receive expression: after
v, ok := <-ch
`ok` is `false` if there are no more values to receive and the channel is closed.
The loop `for`i`:=`range`c` receives values from the channel repeatedly until it is closed.
*Note:* Only the sender should close a channel, never the receiver. Sending on a closed channel will cause a panic.
*Another*note*: Channels aren't like files; you don't usually need to close them. Closing is only necessary when the receiver must be told there are no more values coming, such as to terminate a `range` loop.
.play prog/range-and-close.go
* Select
The `select` statement lets a goroutine wait on multiple communication operations.
A `select` blocks until one of its cases can run, then it executes that case. It chooses one at random if multiple are ready.
.play prog/select.go
* Default Selection
The `default` case in a `select` is run if no other case is ready.
Use a `default` case to try a send or receive without blocking:
select {
case i := <-c:
// use i
default:
// receiving from c would block
}
.play prog/default-selection.go
* Exercise: Equivalent Binary Trees
There can be many different binary trees with the same sequence of values stored at the leaves. For example, here are two binary trees storing the sequence 1, 1, 2, 3, 5, 8, 13.
.image static/tree.png
A function to check whether two binary trees store the same sequence is quite complex in most languages. We'll use Go's concurrency and channels to write a simple solution.
This example uses the `tree` package, which defines the type:
type Tree struct {
Left *Tree
Value int
Right *Tree
}
* Exercise: Equivalent Binary Trees
*1.* Implement the `Walk` function.
*2.* Test the `Walk` function.
The function `tree.New(k)` constructs a randomly-structured binary tree holding the values `k`, `2k`, `3k`, ..., `10k`.
Create a new channel `ch` and kick off the walker:
go Walk(tree.New(1), ch)
Then read and print 10 values from the channel. It should be the numbers 1, 2, 3, ..., 10.
*3.* Implement the `Same` function using `Walk` to determine whether `t1` and `t2` store the same values.
*4.* Test the `Same` function.
`Same(tree.New(1),`tree.New(1))` should return true, and `Same(tree.New(1),`tree.New(2))` should return false.
.play prog/exercise-equivalent-binary-trees.go
* Exercise: Web Crawler
In this exercise you'll use Go's concurrency features to parallelize a web crawler.
Modify the `Crawl` function to fetch URLs in parallel without fetching the same URL twice.
.play prog/exercise-web-crawler.go
* Where to Go from here...
#appengine: You can get started by
#appengine: [[http://golang.org/doc/install/][installing Go]] or downloading the
#appengine: [[http://code.google.com/appengine/downloads.html#Google_App_Engine_SDK_for_Go][Go App Engine SDK]].
#appengine: Once you have Go installed, the
The
[[http://golang.org/doc/][Go Documentation]] is a great place to
#appengine: continue.
start.
It contains references, tutorials, videos, and more.
To learn how to organize and work with Go code, watch [[http://www.youtube.com/watch?v=XCsL89YtqCs][this screencast]] or read [[http://golang.org/doc/code.html][How to Write Go Code]].
If you need help with the standard library, see the [[http://golang.org/pkg/][package reference]]. For help with the language itself, you might be surprised to find the [[http://golang.org/ref/spec][Language Spec]] is quite readable.
To further explore Go's concurrency model, watch
[[http://www.youtube.com/watch?v=f6kdp27TYZs][Go Concurrency Patterns]]
([[http://talks.golang.org/2012/concurrency.slide][slides]])
and
[[https://www.youtube.com/watch?v=QDDwwePbDtw][Advanced Go Concurrency Patterns]]
([[http://talks.golang.org/2013/advconc.slide][slides]])
and read the
[[http://golang.org/doc/codewalk/sharemem/][Share Memory by Communicating]]
codewalk.
To get started writing web applications, watch
[[http://vimeo.com/53221558][A simple programming environment]]
([[http://talks.golang.org/2012/simple.slide][slides]])
and read the
[[http://golang.org/doc/articles/wiki/][Writing Web Applications]] tutorial.
The [[http://golang.org/doc/codewalk/functions/][First Class Functions in Go]] codewalk gives an interesting perspective on Go's function types.
The [[http://blog.golang.org/][Go Blog]] has a large archive of informative Go articles.
Visit [[http://golang.org][golang.org]] for more.