-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathtour.article
850 lines (446 loc) · 30.7 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
A Tour of Go
The Go Authors
http://golang.org
* Hello, 안녕
[[http://golang.org][Go 프로그래밍 언어]] 투어에 오신 것을 환영합니다.
이 투어는 3개의 섹션으로 되어 있고, 각 섹션의 마지막 부분에는 좀더 완벽한 이해를 돕기 위해 연습문제가 준비되어 있습니다.
지금 Run 버튼을 클릭해보거나 키보드에서 Shift-Enter 키를 눌러보세요. 옆의 Go 소스가 컴파일되고 실행될 겁니다. 실행 결과는 코드 밑에 표시됩니다.
이 투어에 있는 많은 예제 프로그램들은 Go가 다른 언어들과 어떤 차이점이 있는지 보여줄 것이고, 여러분이 Go를 배우는데 출발점이 될 것입니다.
소스를 수정하고 다시 한번 실행해보세요.
이제 다음으로 넘어갈 준비가 되었으면, Next 버튼을 클릭하거나 PageDown 키를 누르세요.
.play prog/hello.go
* Go local
이 투어는 다른 나라 언어로도 이용할 수 있습니다:
- [[http://go-tour-br.appspot.com/][Brazilian Portuguese — Português do Brasil]]
- [[http://go-tour-he.appspot.com/][Hebrew — עִבְרִית]]
- [[http://go-tour-zh.appspot.com/][Chinese — 普通话]]
- [[http://go-tour-jp.appspot.com/][Japanese — 日本語]]
- [[http://go-tour-kr.appspot.com/][Korean — 한국어]]
계속 하시려면 Next 버튼을 클릭하거나 PageDown 키를 누르세요.
* Go offline
Go Tour는 인터넷 연결없이 stand-alone 프로그램으로도 사용할 수 있습니다.
stand-alone으로 Go Tour를 이용하면 예제 코드들이 로컬 머신에서 빌드되고 실행되기 때문에 보다 빠릅니다. 그리고 웹버전에는 가능하지 않은 추가적인 연습문제들을 포함하고 있습니다.
이 투어를 로컬에서 실행하기 위해 먼저 [[http://golang.org/doc/install/][Go를 설치]] 하고, [[http://code.google.com/p/go-tour/][gotour]]를 설치하기 위해 [[http://golang.org/cmd/go/][go get]]을 명령을 이용하면 됩니다.
go get code.google.com/p/go-tour/gotour
그리고 위 결과로 생긴 `gotour` 를 실행하세요.
오프라인 모드를 사용하지 않고 계속 진행하려면, "next" 버튼이나 PageDown 키를 누르세요.
_(언제든_"index"_버튼을_누르면_원하는_특별한_챕터로_이동할_수_있습니다.)_
* 패키지(Packages)
모든 Go 프로그램은 패키지로 구성되어 있습니다.
프로그램은 `main` 패키지에서부터 실행을 시작합니다.
이 프로그램은 `"fmt"` 와 `"math"` 패키지를 import 해서 사용하고 있습니다.
패키지 이름은 디렉토리 경로의 마지막 이름을 사용하는 것이 규칙입니다.
예를 들어 `"path/filepath"` 를 사용한다면 패키지명은 `filepath` 입니다.
.play prog/packages.go
* 임포트 (Imports)
이 코드에서는 여러개의 `"package"` 를 소괄호로 감싸서 import를 표현합니다. 아래와 같이 import 문장을 여러번 사용할 수 도 있습니다.
import "fmt"
import "math"
.play prog/imports.go
* 익스포트 (Exported names)
패키지를 Import 하면 패키지가 외부로 export 한 것들(메서드나 변수, 상수 등)에 접근할 수 있습니다.
Go에서는 첫 문자가 대문자로 시작하면 그 패키지를 사용하는 곳에서 접근할 수 있는 exported name이 됩니다.
예를 들어 `Foo` 와 `FOO` 는 외부에서 참조할 수 있지만 `foo` 는 참조 할 수 없습니다.
예제를 실행해보세요. 에러가 발생한다면 `math.pi` 를 `math.Pi` 로 변경 해보세요.
.play prog/exported-names.go
* 함수 (1)
함수는 매개변수(인자)를 가질 수 있습니다.
예를 들어 `add` 라는 함수는 두개의 `int` 타입 매개변수를 받습니다.
C, C++, Java 언어와 다르게 매개변수의 타입은 변수명 _뒤에_ 명시합니다.
(타입을 왜 변수명 뒤에 명시하는지에 대한 자세한 내용은 [[http://golang.org/doc/articles/gos_declaration_syntax.html][Go's declaration syntax]]를 참고하시기 바랍니다. 간단히 설명하면 코드를 왼쪽에서 오른쪽으로 읽을 때 자연스럽게 읽기 위해서 입니다.)
.play prog/functions.go
* 함수 (2)
두 개 이상의 매개변수가 같은 타입(type)일 때, 같은 타입을 취하는 마지막 매개변수에만 타입을 명시하고 나머지는 생략할 수 있습니다.
예를 들어
x int, y int
과 같은 문장은 아래와 같이 표현할 수 있습니다.
x, y
.play prog/functions-continued.go
* 여러 개의 결과 (Multiple results)
하나의 함수는 여러 개의 결과를 반환할 수 있습니다.
예제 코드에서의 함수는 두개의 문자열을 반환합니다.
.play prog/multiple-results.go
* 이름이 정해진 결과 (Named results)
함수는 매개변수를 취합니다. Go에서 함수는 여러 개의 결과를 반환할 수 있습니다. 반환 값에 이름을 부여하면 변수처럼 사용할 수도 있습니다.
결과에 이름을 붙히면, 반환 값을 지정하지 않은 `return` 문장으로 결과의 현재 값을 알아서 반환합니다.
.play prog/named-results.go
* 변수 (Variables)
변수를 선언을 위해 `var` 을 사용합니다.
함수의 매개변수처럼 타입은 문장 끝에 명시합니다.
.play prog/variables.go
* 변수의 초기화
변수 선언과 함께 변수 각각을 초기화를 할 수 있습니다.
초기화를 하는 경우 타입(type)을 생략할 수 있습니다. 변수는 초기화 하고자 하는 값에 따라 타입이 결정됩니다.
.play prog/variables-with-initializers.go
* 변수의 짧은 선언
함수 내에서 `:=` 을 사용하면 `var` 과 명시적인 타입(e.g. int, bool) 을 생략할 수 있습니다.
(그러나 함수 밖에서는 `:=` 선언을 사용할 수 없습니다.)
.play prog/short-variable-declarations.go
* 상수 (Constants)
상수는 `const` 키워드와 함께 변수처럼 선언합니다.
상수는 문자(character), 문자열(string), 부울(boolean) 등(values)일 수 있습니다.
.play prog/constants.go
* 숫자형 상수 (Numeric Constants)
숫자형 상수는 _정밀한_값(values)_ 을 표현할 수 있습니다.
타입을 지정하지 않은 상수는 문맥(context)에 따라 타입을 가지게 됩니다.
코드를 통해 `needInt(Big)` 는 어떤 결과를 출력할지 실험해보세요.
.play prog/numeric-constants.go
* For (반복문 for)
Go 언어는 반복문이 `for` 밖에 없습니다.
기본적인 `for` 반복문은 C와 Java 언어와 거의 유사합니다. 다른점은 소괄호 ( )가 필요하지 않다는 것입니다.
하지만 실행문을 위한 중괄호 { } 는 필요합니다.
.play prog/for.go
* For (2)
C와 Java에서 처럼 전.후 처리를 제외하고 조건문만 표현할 수도 있습니다.
.play prog/for-continued.go
* Go에서 "While" 사용하기
이전의 예제에서 처럼 조건문만 표시하면 C언어에서 `while` 을 사용하듯 `for` 를 사용할 수 있습니다.
.play prog/for-is-gos-while.go
* 무한 루프
for에서 조건문을 생략하면 무한 루프를 간단하게 표현할 수 있습니다.
.play prog/forever.go
* 조건문 (If)
`if` 문은 C와 Java와 비슷합니다. 조건 표현을 을 위해 `(`)` 는 사용하지 않습니다. 하지만 실행문을 위한 `{`}` 는 반드시 작성해야합니다.
(For문과 비슷하죠?)
.play prog/if.go
* If와 짧은 명령 사용하기
`for` 처럼 `if` 에서도 조건문 앞에 짧은 문장을 실행할 수 있습니다.
예제에서는 조건을 비교하기 전에 `v`:=`math.Pow(x,n)` 을 실행했습니다.
짧은 실행문을 통해 선언된 변수는 `if` _안쪽_범위(scope)_ 에서 만 사용할 수 있습니다.
(예제 코드의 `pow` 함수에서 `return` 전에 `v` 를 사용해보세요.)
.play prog/if-with-a-short-statement.go
* If와 else
`if` 에서 짧은 명령문을 통해 선언된 변수는 `else` 블럭 안에서도 사용할 수 있습니다.
.play prog/if-and-else.go
* Exercise: Loops and Functions
As a simple way to play with functions and loops, implement the square root function using Newton's method.
In this case, Newton's method is to approximate `Sqrt(x)` by picking a starting point _z_ and then repeating:
To begin with, just repeat that calculation 10 times and see how close you get to the answer for various values (1, 2, 3, ...).
Next, change the loop condition to stop once the value has stopped changing (or only changes by a very small delta). See if that's more or fewer iterations. How close are you to the [[http://golang.org/pkg/math/#Sqrt][math.Sqrt]]?
Hint: to declare and initialize a floating point value, give it floating point syntax or use a conversion:
z := float64(1)
z := 1.0
.play prog/exercise-loops-and-functions.go
* 기본 자료형
Go의 기본 자료형은 아래와 같습니다.
bool
string
int int8 int16 int32 int64
uint uint8 uint16 uint32 uint64 uintptr
byte // uint8의 다른 이름(alias)
rune // int32의 다른 이름(alias)
// 유니코드 코드 포인트 값을 표현합니다.
float32 float64
complex64 complex128
.play prog/basic-types.go
* 구조체 (Structs)
`struct` 는 필드(데이터)들의 조합입니다.
(그리고 `type` 선언으로 struct의 이름을 지정할 수 있습니다.)
.play prog/structs.go
* 구조체 필드
구조체에 속한 필드(데이터)는 dot(.) 으로 접근합니다.
.play prog/struct-fields.go
* 포인터 (Pointers)
Go에는 포인터가 있지만 포인터 연산은 불가능합니다.
구조체 변수는 구조체 포인터를 이용해서 접근 할 수 있습니다.
포인터를 이용하는 간접적인 접근은 실제 구조체에도 영향을 미칩니다.
.play prog/pointers.go
* 구조체 리터럴 (Struct Literals)
구조체 리터럴은 필드와 값을 나열해서 구조체를 새로 할당하는 방법입니다.
원하는 필드를 `{Name:`value}` 구문을 통해 할당할 수 있습니다. (필드의 순서는 상관 없습니다.)
특별한 접두어 `&` 를 사용하면 구조체 리터럴에 대한 포인터를 생성할 수 있습니다.
.play prog/struct-literals.go
* new 함수
`new(T)` 는 모든 필드가 _0(zero_value)_ 이 할당된 `T` 타입의 포인터를 반환합니다.
( _zero_value_ 는 숫자 타입에서는 `0` , 참조 타입에서는 `nil` 을 뜻합니다 )
var t *T = new(T)
또는
t := new(T)
위의 변수 t는 `T` 에서 반환된 포인터를 가집니다.
.play prog/the-new-function.go
* 슬라이스 (Slices)
슬라이스는 배열의 값을 가리킵니다(point). 그리고 배열의 길이를 가지고 있습니다.
`[]T` 는 타입 `T` 를 가지는 요소의 슬라이스(slice) 입니다.
.play prog/slices.go
* 슬라이스 자르기 (Slicing slices)
슬라이스는 재분할 할 수도 있고, 같은 배열을 가리키는(point) 새로운 슬라이스를 만들 수 도 있습니다.
예제로 살펴보면
s[lo:hi]
위의 표현은 `lo` 에서 `hi-1` 의 요소(element)를 포함하는 슬라이스입니다. 따라서
s[lo:lo]
는 빈(empty) 슬라이스 이고
s[lo:lo+1]
는 하나의 요소를 가집니다.
.play prog/slicing-slices.go
* 슬라이스 만들기
슬라이스는 `make` 함수로 만들 수 있습니다. 이렇게 생성된 슬라이스는 0을 할당한 배열을 생성하고, 그것을 참조(refer)합니다.
a := make([]int, 5) // len(a)=5
`make` 함수의 세번째 매개변수로 용량(capacity)를 제한할 수 있습니다.
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
* 빈 슬라이스
슬라이스의 zero value는 `nil` 입니다.
nil 슬라이스는 길이와 최대 크기가 0입니다.
(슬라이스에 대해 더 알고 싶다면 다음 글을 읽어보세요. [[http://golang.org/doc/articles/slices_usage_and_internals.html][Slices: usage and internals]])
.play prog/nil-slices.go
* 레인지 (Range, 범위)
`for` 반복문에서 `range` 를 사용하면 슬라이스나 맵을 순회(iterates)할 수 있습니다.
.play prog/range.go
* 레인지 (2)
`_` 를 이용해서 인덱스(index)나 값(value)를 무시할 수 있습니다.
만약 인덱스만 필요하다면 “ `,`value` ” 부분을 다 제거하면 됩니다.
for i, value := range pow {
pow[i] = 1 << uint(i)
}
에서
for i := range pow {
pow[i] = 1 << uint(i)
}
처럼 사용할 수 있습니다.
.play prog/range-continued.go
* Exercise: Slices
Implement `Pic` . It should return a slice of length `dy` , each element of which is a slice of `dx` 8-bit unsigned integers. When you run the program, it will display your picture, interpreting the integers as grayscale (well, bluescale) values.
The choice of image is up to you. Interesting functions include `x^y`, `(x+y)/2`, and `x*y` .
(You need to use a loop to allocate each `[]uint8` inside the `[][]uint8`.)
(Use `uint8(intValue)` to convert between types.)
.play prog/exercise-slices.go
* 맵 (Maps)
맵은 값에 키를 지정합니다.
맵은 반드시 사용하기 전에 `make` 를 명시해야합니다. (주의: `new` 가 아닙니다)
`make` 를 수행하지 않은 `nil` 에는 값을 할당할 수 없습니다.
.play prog/maps.go
* 맵 리터럴 (Map literals)
맵 리터럴은 구조체 리터럴과 비슷하지만 `key` 를 반드시 지정해야 합니다.
.play prog/map-literals.go
* 맵 리터럴 (2)
만약 가장 상위의 타입이 타입명이라면 리터럴에서 타입명을 생략해도 됩니다.
"Bell Labs": {40.68433, -74.39967}
또는
"Bell Labs": Vertex{40.68433, -74.39967}
는 같은 표현입니다.
.play prog/map-literals-continued.go
* 맵 다루기 (Mutating Maps)
맵 `m` 의 요소를 삽입하거나 수정하기:
m[key] = elem
요소 값 가져오기:
elem = m[key]
요소 지우기:
delete(m, key)
키의 존재 여부 확인하기:
elem, ok = m[key]
위의 `ok` 의 값은 `m` 에 `key` 가 존재한다면 `true` 존재하지 않으면 `false` , `elem` 은 타입에 따라 _0(zero_value)_ 가 됩니다.
이처럼 `map` 을 읽을 때, 존재하지 않는 `key` 의 반환 값은 타입에 맞는 _zero_value_ 입니다.
.play prog/mutating-maps.go
* Exercise: Maps
Implement `WordCount` . It should return a map of the counts of each “word” in the string `s` . The `wc.Test` function runs a test suite against the provided function and prints success or failure.
You might find [[http://golang.org/pkg/strings/#Fields][strings.Fields]] helpful.
.play prog/exercise-maps.go
* 함수 값 (Function values)
함수도 값 입니다.
(번역자 : 맨 아래 `hypot(3,4)` 의 hypot 함수를 Println함수의 인자값 처럼 사용 하고 있습니다.)
.play prog/function-values.go
* 함수 클로져 (Function closures)
그리고 함수는 클로져(full closures) 입니다.
코드에서 `adder` 함수는 클로져(closure)를 반환합니다.
각각의 클로져는 자신만의 `sum` 변수를 가집니다.
.play prog/function-closures.go
* Exercise: Fibonacci closure
Let's have some fun with functions.
Implement a `fibonacci` function that returns a function (a closure) that returns successive fibonacci numbers.
.play prog/exercise-fibonacci-closure.go
* 스위치 (Switch)
다른 일반적인 언어를 아는 분이라면 `switch` 에 대해서 잘 알 것입니다.
다른 언어와 다른점은 case의 코드 실행을 마치면 알아서 break를 한다는 점입니다.
( `fallthrough` 로 끝나는 case는 스스로 break를 하지 않습니다 )
.play prog/switch.go
* 스위치 동작 순서
스위치의 각 조건은 위에서 아래로 평가합니다. 만약 조건이 참인 case를 찾으면 평가를 마칩니다.
(예를 들어
switch i {
case 0:
case f():
}
에서 `i==0` 이라면 `f()` 는 실행하지 않습니다)
.play prog/switch-evaluation-order.go
* 조건을 생략한 스위치
스위치에서 조건을 생략하면 " `switch` `true` " 와 같습니다.
만약 긴 if-then-else 를 작성해야 할 때, 이 구조를 사용하면 코드를 깔끔하게 작성할 수 있습니다.
.play prog/switch-with-no-condition.go
* Advanced Exercise: Complex cube roots
Let's explore Go's built-in support for complex numbers via the `complex64` and `complex128` types. For cube roots, Newton's method amounts to repeating:
Find the cube root of 2, just to make sure the algorithm works. There is a [[http://golang.org/pkg/math/cmplx/#Pow][Pow]] function in the `math/cmplx` package.
.play prog/advanced-exercise-complex-cube-roots.go
* 메소드와 인터페이스
* 메소드 (Methods)
고에는 클래스가 없습니다. 하지만 메소드를 구조체(struct)에 붙일 수 있습니다.
_메소드_리시버(method_receiver)_ 는 `func` 키워드와 메소드의 이름 사이에 인자로 들어갑니다.
.play prog/methods.go
* 메소드 (2)
사실 메소드는 구조체(struct) 뿐 아니라 아무 타입(type)에나 붙일 수 있습니다.
다른 패키지에 있는 타입이나 기본 타입들에 메소드를 붙이는 것은 불가능합니다.
.play prog/methods-continued.go
* 포인터 리시버를 가지는 메소드
메소드는 이름이 있는 타입 또는 이름이 있는 타입의 포인터와 연결할 수 있습니다.
방금 두 개의 `Abs` 메소드를 보았는데, 하나는 `*Vertex` 라는 포인터 타입의 메소드고, 다른 하나는 `MyFloat` 값 타입의 메소드 입니다.
포인터 리시버를 사용하는 이유는 두 가지 입니다. 첫째, 메소드가 호출될 때 마다 값이 복사되는 것(큰 구조체 타입인 경우 값이 복사되는 것은 비효율적이죠)을 방지하기 위함 입니다. 다른 이유는 메소드에서 리시버 포인터가 가르키는 값을 수정하기 위함 입니다.
`*Vertex` 타입의 리시버 대신 `Vertex` 를 사용하도록 메소드 `Abs` 와 `Scale` 의 선언부분을 바꿔 보세요.
`v` 를 `Vertex` 타입으로 받으면 `Scale` 메소드가 더 이상 동작하지 않습니다. `Scale` 은 `v` 를 바꾸는데, `v` 가 (포인터가 아닌) 값 타입이기 때문에 `Vertex` 타입인 복사본에 작업을 하기 때문에 원래의 값은 바뀌지 않습니다.
`Abs` 의 경우는 다릅니다. 여기서는 `v` 를 읽기만 하기 때문에, (포인터가 가르키는) 원래의 값이건 복사본이건 상관이 없게 됩니다.
.play prog/methods-with-pointer-receivers.go
* 인터페이스 (Interface)
인터페이스는 메소드의 집합으로 정의됩니다.
그 메소드들의 구현되어 있는 타입의 값은 모두 인터페이스 타입의 값이 될 수 있습니다.
.play prog/interfaces.go
* 인터페이스 암시적으로 충족됩니다
타입이 인터페이스의 메소드들을 구현하면 인터페이스를 구현한 게 됩니다.
_이를_위해_명시적으로_선언할_게_없습니다._
암시적 인터페이스는 인터페이스를 정의한 패키지로 부터 구현 패키지를 분리(decouple)해 줍니다. 다른 의존성 또한 없음은 물론입니다.
이 특징은 상세하게 인터페이스를 정의하게 독려합니다. 모든 구현을 찾아 새 인터페이스 이름으로 태그할 필요가 없기 때문입니다.
[[http://golang.org/pkg/io/][패키지 io]]에 `Reader` 와 `Writer` 가 정의되어 있습니다. 따로 정의할 필요가 없습니다.
.play prog/interfaces-are-satisfied-implicitly.go
* 에러(error)
에러 문장(string)으로 자신을 표현할 수 있는 것은 모두 에러입니다. 이 아이디어는 문자열(string)을 반환하는 하나의 메소드 `Error` 로 구성된 내장 인터페이스 타입 `error` 에서 나왔습니다.
type error interface {
Error() string
}
`fmt` 패키지의 다양한 출력 루틴들은 `error` 의 출력을 요청받았을 때 자동으로 이 메소드를 호출합니다.
.play prog/errors.go
* 연습: 에러
당신의 `Sqrt` 함수를 이전 연습에서 복사하고 `error` 값을 반환하도록 수정하십시오.
`Sqrt` 함수는 복소수를 지원하지 않기 때문에, 음수가 주어지면 `nil` 이 아닌 에러 값을 반환해야 합니다.
새로운 타입을 만드십시오.
type ErrNegativeSqrt float64
and make it an `error` by giving it a
그리고 아래 메소드를 구현함으로써 그 타입이 `error` 가 되게 하십시오.
func (e ErrNegativeSqrt) Error() string
이는 `ErrNegativeSqrt(-2).Error()` 가 `"cannot`Sqrt`negative`number:`-2"` 를 반환하는 그러한 메소드입니다.
*Note:* `Error` 메소드 내에서 `fmt.Print(e)` 를 호출하면 이 프로그램을 무한루프에 빠질 것입니다. `e` 를 바꿈으로써 이 문제를 피할 수 있습니다. 왜 그럴까요?
음수가 주어졌을 때 `ErrNegativeSqrt` 값을 반환하도록 당신의 `Sqrt` 함수를 바꾸십시오.
.play prog/exercise-errors.go
* 웹 서버
[[http://golang.org/pkg/net/http/][Package http]] 는 `http.Handler` 를 구현한 어떠 값을 사용하여 HTTP 요청(requests)을 제공합니다.
package http
type Handler interface {
ServeHTTP(w ResponseWriter, r *Request)
}
이 예제에서, `Hello` 라는 타입은 `http.Handler` 를 구현합니다.
이 코드를 로컬에서 실행하고, [[http://localhost:4000/][http://localhost:4000/]] 에 접속해보세요.
.play prog/web-servers.go
* 연습: HTTP 핸들러
아래 나오는 타입을 구현하고 그 타입의 ServeHTTP 메소드를 정의하십시오. 그 메소드를 당신의 웹 서버에서 특정 경로를 처리할 수 있도록 등록하십시오.
type String string
type Struct struct {
Greeting string
Punct string
Who string
}
예컨대, 당신은 아래와 같이 핸들러를 등록할 수 있어야 합니다.
http.Handle("/string", String("I'm a frayed knot."))
http.Handle("/struct", &Struct{"Hello", ":", "Gophers!"})
.play prog/exercise-http-handlers.go
* 이미지
[[http://golang.org/pkg/image/#Image][Package image]] 는 `Image` 인터페이스를 정의합니다.
package image
type Image interface {
ColorModel() color.Model
Bounds() Rectangle
At(x, y int) color.Color
}
(모든 세부사항에 대한 것은 [[http://golang.org/pkg/image/#Image][이 문서]] 를 참고하십시오.)
또한, `color.Color` 와 `color.Model` 는 인터페이스이지만, 미리 정의된 구현체인 `color.RGBA` 와 `color.RGBAModel` 을 사용함으로써 그 인터페이스를 무시할 수 있습니다.
.play prog/images.go
* 연습: 이미지
이전의 연습에서 당신이 작성한 그림 생성기를 기억하십니까? 다른 생성기를 만들어봅시다. 하지만 이번에는 데이터의 슬라이스 대신에 `image.Image` 의 구현체를 반환할 것입니다.
당신 자신의 `Image` 타입을 정의하시고, [[http://golang.org/pkg/image/#Image][필수 함수들]] 을 구현하신 다음, `pic.ShowImage` 를 호출하십시오.
`Bounds` 는 `image.Rect(0,`0,`w,`h)` 와 같은 `image.Rectangle` 을 반환해야 합니다.
`ColorModel` 은 `color.RGBAModel` 을 반환해야 합니다.
`At` 은 하나의 컬러를 반환해야 합니다; 지난 그림 생성기에서 값 `v` 는 `color.RGBA{v,`v,`255,`255}` 와 같습니다.
.play prog/exercise-images.go
* 연습: Rot13 Reader
어떤 식으로든 스트림을 수정하여 다른 `io.Reader` 를 감싸는 [[http://golang.org/pkg/io/#Reader][io.Reader]] 는 흔한 패턴입니다.
예컨대, [[http://golang.org/pkg/compress/gzip/#NewReader][gzip.NewReader]] 함수는 `io.Reader` (gzip으로 압축된 데이터의 스트림) 를 가지고, `io.Reader` (압축 해제된 데이터의 스트림) 를 구현한 `*gzip.Reader` 를 반환합니다.
[[http://en.wikipedia.org/wiki/ROT13][ROT13]] 치환 암호화를 모든 알파벳 문자에 적용함으로써 스트림을 수정하며 `io.Reader` 를 구현하고 `io.Reader` 로 부터 읽는 `rot13Reader` 를 구현하십시오.
`rot13Reader` 타입은 당신을 위해 제공됩니다. 이 타입의 `Read` 함수를 구현함으로써 `io.Reader` 을 만들어 보십시오.
.play prog/exercise-rot-reader.go
* 동시성
* 고루틴(Goroutines)
_고루틴_ 은 Go 런타임에 의해 관리되는 경량 쓰레드입니다.
go f(x, y, z)
위의 코드는 새로운 고루틴을 시작시킵니다.
f(x, y, z)
현재의 고루틴에서 `f` , `x` , `y` , `z` 가 평가(evaluation)되고, 새로운 고루틴에서 `f` 가 수행(execution)됩니다.
고루틴은 동일한 주소 공간에서 실행되므로, 공유되는 자원으로의 접근은 반드시 동기화 되어야 합니다. `[[http://golang.org/pkg/sync/][sync]]` 패키지가 이를 위해 유용한 기본 기능을 제공합니다. Go 에서는 그외에도 다양한 기본 기능을 제공하니 크게 필요치 않을 테지만요. (다음 슬라이드를 보세요.)
.play prog/goroutines.go
* 채널(Channels)
채널은 채널 연산자 `<-` 를 이용해 값을 주고 받을 수 있는, 타입이 존재하는 파이프입니다.
ch <- v // v 를 ch로 보냅니다.
v := <-ch // ch로부터 값을 받아서
// v 로 넘깁니다.
(데이터가 화살표 방향에 따라 흐릅니다.)
맵이나 슬라이스처럼, 채널은 사용되기 전에 생성되어야 합니다:
ch := make(chan int)
기본적으로, 송/수신은 상대편이 준비될 때까지 블록됩니다. 이런 특성이 고루틴이 명시적인 락이나 조건 없이도 동기화 될 수 있도록 돕습니다.
.play prog/channels.go
* 버퍼링되는 채널
채널은 _버퍼링_ 될 수 있습니다. `make` 에 두번째 인자로 버퍼 용량을 넣음으로써 해당 용량만큼 버퍼링되는 채널을 생성할 수 있습니다:
ch := make(chan int, 100)
버퍼링되는 채널로의 송신은 버퍼가 꽉 찰 때까지 블록됩니다. 수신측은 버퍼가 빌 때 블록됩니다.
예제를 수정해서 버퍼를 넘치게 해보고 어떻게 동작하는지 확인해 보세요.
.play prog/buffered-channels.go
* Range와 Close
데이터 송신측은 더이상 보낼 값이 없다는 것을 알리기 위해 채널을 `close` 할 수 있습니다. 수신측은 다음과 같이 수신 코드에 두번째 인자를 줌으로써 채널이 닫혔는지 테스트 할 수 있습니다.
v, ok := <-ch
채널이 이미 닫혔고 더이상 받을 값이 없다면 `ok` 는 `false` 가 됩니다.
`for`i`:=`range`c` 반복문은 채널이 닫힐 때까지 계속해서 값을 받습니다.
*주의:* 송신측만 채널을 닫을 수 있습니다. 수신측에선 불가능합니다. 이미 닫힌 채널에 데이터를 보내면 패닉이 일어납니다.
*또하나의*주의*: 채널은 파일과 다릅니다; 항상 닫을 필요는 없습니다. 채널을 닫는 행위는 오로지 수신측에게 더이상 보낼 값이 없다고 말해야 할때만 행해지면 됩니다. `range` 루프를 종료시켜야 할 때처럼요.
.play prog/range-and-close.go
* 셀렉트(Select)
`select` 구문은 고루틴이 다수의 통신 동작으로부터 수행 준비를 기다릴 수 있게 합니다.
`select` 는 `case` 구문으로 받는 통신 동작들 중 하나가 수행될 수 있을 때까지 수행을 블록합니다. 다수의 채널이 동시에 준비되면 그 중 하나를 무작위로 선택합니다.
.play prog/select.go
* 셀렉트의 디폴트(default) 케이스
`select` 의 `default` 케이스는 현재 수행 준비가 완료된 케이스가 없을 때 수행됩니다.
블로킹 없이(비동기적인) 송/수신을 하고자 할 때 `default` 케이스를 사용하세요.
select {
case i := <-c:
// i를 사용
default:
// c로부터의 수신은 블록된 상태
}
.play prog/default-selection.go
* 연습: 동등한 이진 트리
노드(leaf)들에 있는 값들의 정렬 순열는 같지만 생김새가 다른 이진트리가 있을 수 있습니다. 예를들어, 다음 그림의 두 이진 트리를 정렬 순열는 1, 1, 2, 3, 5, 8, 13 으로 같습니다.
대부분의 프로그래밍 언어에서 두 이진 트리가 같은 순열인지를 검사하는 함수의 구현은 복잡합니다. 이제 고의 동시성과 채널을 사용한 단순한 방법으로 해결해 봅시다.
이 예제는 다음의 `Tree` 구조체가 정의된 `tree` 패키지를 사용합니다.
type Tree struct {
Left *Tree
Value int
Right *Tree
}
* 연습: 동등한 이진 트리
*1.* `Walk` 함수를 구현하세요.
*2.* `Walk` 함수를 테스트 해 보세요.
함수 `tree.New(k)` 는 `k` , `2k` , `3k` , ..., `10k` 의 값을 가지는, 무작위로 구성된 이진트리를 만들어 냅니다.
채널 `ch` 를 만들고, 작성한 `Walk` 함수의 인자로 넣어 줍니다.
go Walk(tree.New(1), ch)
이제 채널에서 10개의 값을 읽어 봅니다. 읽힌 값은 1, 2, 3, ..., 10 이어야 합니다.
*3.* `Walk` 함수를 사용해 두 트리 `t1` 과 `t2` 이 값은 값들을 가지고 있는지 비교하는 `Same` 함수를 구현해 보세요.
*4.* `Same` 함수를 테스트 해 보세요.
`Same(tree.New(1),`tree.New(1))` 의 수행결과는 true, `Same(tree.New(1),`tree.New(2))` 의 수행 결과는 false 이어야 합니다.
.play prog/exercise-equivalent-binary-trees.go
* 연습: 웹 크롤러
이 연습에서는 고의 동시성 기능을 사용해 웹 크롤러를 병렬화 해 볼 것입니다.
`Crawl` 함수를 고쳐서, 같은 URL을 두번 가져오는 중복을 피하면서 URL들을 병렬로 패치하게 고쳐보세요.
.play prog/exercise-web-crawler.go
* 더 살펴볼 곳 들...
우선 [[http://golang.org/doc/][Go 문서]] 사이트에서 시작하는 것이 좋습니다. 여기에서 레퍼런스, 튜토리얼, 비디오 등의 자료를 볼 수 있습니다.
고 코드를 구성하기와 고로 작업하는 방법을 배우려면, [[http://www.youtube.com/watch?v=XCsL89YtqCs][이 스크린캐스트]]를 보거나, [[http://golang.org/doc/code.html][고 코드 작성 방법]]를 읽어 보세요.
표준 라이브러리에 대한 도움이 필요하면, [[http://golang.org/pkg/][패키지 레퍼런스]]를 살펴보세요. 고 언어 자체에 대해서는 [[http://golang.org/ref/spec][언어 스펙]]이 도움이 되며, 아마 꽤 쉽게 스펙문서를 읽을 수 있음에 놀라게 될 것입니다.
더 나아가 고의 동시성(concurrency) 모델을 살펴보려면 코드워크, [[http://golang.org/doc/codewalk/sharemem/][통신으로 메모리 공유하기]]를 보세요.
코드워크, [[http://golang.org/doc/codewalk/functions/][First Class Functions in Go]]에서는 고의 함수 타입에 관련된 흥미로운 관점을 제공합니다.
공식 블로그, [[http://blog.golang.org/][Go ]]에는 유익한 기사들이 많이 있습니다.
공식 사이트 [[http://golang.org][golang.org]]를 방문해 더 살펴보세요.
번역: [[https://developers.google.com/groups/chapter/112714242728066184635/][한국 Go 언어 커뮤니티(GDG Korea Golang)]]