2. Why Go?
• 클라우드 시스템 관련 Core들이 Go로 작성되고 있음.
• 특히 Docker는 Go의 성공사례
• 기존 PaaS를 분석하려고 하니 Go를 읽을 줄 알아야한다.
• Github의 Go 프로젝트 59,145개 (2015.3.14기준)
3. Top Github Projects in Go
• docker/docker
Docker - the open-source application container
engine
• limetext/lime
Open source API-compatible alternative to the
text editor Sublime Text
• syncthing/syncthing
Open Source Continuous File Synchronization
• golang/go
The Go programming language
• GoogleCloudPlatform/kubernetes
Container Cluster Manager from Google
• go-martini/martini
Classy web framework for Go
• joewalnes/websocketd
Turn any program that uses STDIN/STDOUT into a
WebSocket server. Like inetd, but for
WebSockets.
• github/hub
hub helps you win at git.
• coreos/etcd
A highly-available key value store for shared
configuration and service discovery
• astaxie/build-web-application-with-golang
A golang ebook intro how to build a web with
golang
2015.3.14 기준으로 뽑아봤어요
4. 참고문서
• golang-korea
– go 개발언어 관련 자료를 한국어로 번역하는 프로젝트
– https://code.google.com/p/golang-korea/
• 그외의 인터넷 문서들
5. 기초
형아들~♥ 이제 부터 나의 기초를 보여줄게
난 생긴것 처럼 단순한 아이야~ ♥
자 그럼 Let’s Go~♥
6. Go 는 Object-Oriented 언어인가?
• 맞기도 하고 아니기도 하다.
– http://golang.org/doc/faq#Is_Go_an_object-oriented_language
• 아닌 이유
– 상속관계가 없다. No subclass
• 맞는 이유
– object-oriented 스타일의 프로그래밍을 허용한다. interface제공.
• object-oriented 스타일의 프로그래밍?
– 상속은 제공하지 않으며 interface만 제공.
– implements"라는 선언 필요없음.
– 단순히 해당 인터페이스의 메소드를 구현하기만 하면 인터페이스 사용가능
7. 준비사항
• 홈페이지 : http://golang.org/
• Go SDK 다운로드 : http://golang.org/dl/
• 편집도구 : LiteIDE
– 다운로드 :
http://sourceforge.net/projects/liteide/files/
8. 함수형태
• 리턴값 없음
func f1() { }
• 리턴값 존재
func f1() string {
return “OK”
}
• 리턴값 이름
func f2() (r string) {
r = “OK”
return
}
• struct 내부함수
type Counter struct {
n int
}
func (ctr *Counter) add(int amount) { //리시버 Counter 선언.
ctr.n += amount;
}
func f1() (string, int) {
return “OK”, 1
}
리시버는 나중에 자세하게 나오니까 염려하지마요
9. Go 가시성
• 최상위 type, 함수, method, 상수, 변수 혹은 구조체의
필드나 method의 이름이 대문자로 시작하면 패키지의
사용자는 접근이 가능
• 반면에 소문자일 경우에는 패키지 내부에서만 접근이
가능
10. 진입점
• main 패키지의 main() 함수
package main
func main() {
//무언가를 수행한다.
}
11. 실행과 빌드
• 실행
$ go run 파일명
• 빌드
$ go build
또는
$ go build 파일명
• 빌드결과삭제
$ go clean
13. 그외 모든 타입
bool 불린 true, false
numeric 이전 장에서 설명한 숫자타입
string 문자열. Java와 달리 소문자이다.
array []
slice [] array를 참조한다. ex) arr[2:5]
struct ex) type struct Human { }
pointer *
function func
interface interface
map map
channel chan
14. 키워드
break default func interface select
case defer go map struct
chan else goto package switch
const fallthrough if range type
continue for import return var
15. Java와 다른점 몇가지
• 세미콜론은 생략한다. 하지만 같은줄에 여러명령에는 사용.
a= 1
b= 2
c=1; d=2
• 변수선언에는 var를 사용하고 타입은 맨뒤에 선언
var a int cf) int a
var b string cf) String b
• main함수는 파라미터가 없다. 대신 flag사용
var port = flag.String("port", "8080", "Listening port")
func main() {
flag.Parse()
}
• if, for 에 괄호를 사용하지 않으며, 여는 중괄호({)는 반드시 같은줄에 사용한다.
if x > 1 { .. }
for i:=0; i< 100; i++ {
//구현
}
• 선언과 할당을 동시에 할때는 =가 아닌 := 를 사용한다. 이때 변수타입은 값의 타입으로
추정한다.
price := 2000 var price int = 2000 과 동일.
16. Java와 다른점 몇가지 2
• switch-case 는 break가 필요없다. 기본이 break이며, 필요시 fallthrough 사용.
• try-catch-finally, throw가 없다.
defer finally
raise throw
recover catch
• 포인터존재
var a *Human
a := new(Human)
b := &i
• 사용하지 않는 변수나 import는 컴파일시 에러발생. 제거하거나 주석처리해야한다.
• import 에 alias 를 줄 수 있다.
import “math”
import math2 “my/custom/math”
math2.Average(1,2)
• private , public 이 없다. 대신 함수명이나 변수명이 대문자이면, public이고
소문자이면 private이다.
var Name string public
var price int private
func CallMePublic() public
func callMeInside() private
17. Java와 다른점 몇가지 3
• class라는 keyword가 없다. 대신 struct를 만들고 함수에 struct명을
주어(리시버) class와 동일하게 사용할 수 있다.
• Thread가 없다. 대신 light-weight인 고루틴을 사용한다.
go something() 비동기적 something()함수실행
• 여러값을 동시에 리턴가능하다.
return a,b,c
• 여러값을 동시에 할당가능하다.
var a,b,c int = 1,2,3
• 여러변수를 동시에 선언가능하다. import도 동일.
• 자동형변환이 안된다. 명시적 형변환필요.
var c int = 2000
var d float64 = float64(c) OK. 만약 var d float64 = c 은 에러. var d float64= float32(c))도 에러.
• 배열선업시 괄호는 앞에 쓴다. []int
var (
a int
b string
)
import (
“fmt”
“io”
)
18. 변수선언/할당
• 사용법1
var x string = "Hello World"
• 사용법2
var x string
x = "Hello World"
• 사용법3
x := "Hello World"
> 일반적으로 많이 사용하는 방식. 타입추정.
19. 변수선언/할당2
• 같은줄에 컴마구분으로 여러변수를 동일 타입으로 정의가능
a int, b int , c int , d int a, b, c, d int
a int, b int, c float64, d float64 a, b int, c, d float64
func f(a, b int, c, d float64) {
// do something..
}
func main() {
f(1, 2, 3., 4.)
}
20. 다중값 할당
func f() (int, int) {
return 5, 6
}
func main() {
x, y := f()
}
• 오류와 함께 반환하는 기능은 자주 사용됨.
f, err := os.Open(name, os.O_RDONLY, 0)
if err != nil {
return err
}
//파일 f 사용.
21. 다중값 할당2
• 두값의 SWAP이 편하다
• OLD한 방식
a = 10
b = 30
tmp := b
b = a
a = tmp
• Go 방식
a = 10
b= 30
a, b = b, a
• 여러개도 된다.
a, b, c = b, c, a
22. 다중값 할당3
• 동일한 내용 다른 표현
var (
a int = 1
b int = 2
c int = 3
)
var a int, b int, c int = 1, 2, 3
syntax error: unexpected comma, expecting semicolon or newline or }
var a, b, c int = 1, 2, 3
a, b, c := 1, 2, 3
23. 사용하지 않는 변수
• Go 컴파일러는 사용하지 않는 변수존재시
에러발생.
func main() {
i := 0
}
$ go run test.go
# command-line-arguments
.test.go:16: i declared and not used
24. 문자열 비교
• 자바와 다른점
var x string = "hello"
var y string = "hello"
fmt.Println(x == y)
> true
25. 상수
• 변수
var x string = "Hello World”
• 상수
const x string = "Hello World"
26. 상수
• 상수의 Type을 정하지 않으면, 사용될때context에 의해 정해짐.
const huge = 1 << 100
fmt.Println(huge) constant 1267650600228229401496703205376 overflows
int
fmt.Println(huge >> 40) 4611686018427387904
• iota(Java의 Enum효과)
const (
red = iota // red == 0
blue // blue == 1
green // green == 2
)
27. 다중 정의
• 변수
var (
a = 5
b = 10
)
• 상수
const (
Space = " ”
Newline = "n"
)
28. 다중 정의
• Import
import (
"os"
"fmt"
)
• Type
type(
book struct {
title string
price int
}
coffee struct {
size int
origin string
}
)
29. 루프
• For가 유일한 루프.
• 괄호가 없다.
– 사용법1
for { }
– 사용법2
for i < 10 { }
– 사용법3
for i:=0 ; i < 10; i++ { }
30. 특별 루프
• Range
func main() {
x := [5]int{1,2,3,4}
for i, value := range x {
fmt.Println(value)
}
}
– i : 현재위치(0부터시작)
– value : 현재값. x[i]
• 컴파일시 에러 : i declared and not used
func main() {
x := [5]int{1,2,3,4}
for _, value := range x {
fmt.Println(value)
}
}
– _(언더스코어)는 컴파일러에게 이것이 필요하지 않다고 알려주는 데 사용
31. Switch-Case
• 괄호가 없다.
• 상수이거나 Integer이 필요가 없다. 문자열도 가능.
• Break가 필요없다. 기본적으로 break이며, 통과를 원하면 fallthrough.
• switch 값이 생략된 경우에는 기본값은 true가 된다.
func main() {
str := "3"
switch str {
case "1":
fmt.Println("@1")
case "2": fmt.Println("@2")
default :
fmt.Println("default")
}
}
----
switch {
case i < 0 || i > 0:
fmt.Println(”Non-Zero")
fallthrough
case i == 0 : fmt.Println(”Zero")
}
32. Switch-Case
• 컴마로 여러 조건가능.
switch c {
case ' ', '?', '&', '=', '#', '+', '%':
…
}
33. 배열
• 사용법1
var x [5]int
x[0] = 1; x[1] = 2; ;x[2] = 3; x[3] = 4; x[4] = 5
• 사용법2
x := [5]int{1,2,3,4,5}
• 사용법3
x := [5]int{
1,2,3,4,
5,
}
– 한줄씩 사용할 경우 컴마가 반드시 값뒤에 붙어야하고, 마지막 원소도
반드시 컴마존재.
• 사용법4
x := []int{1,2,3,4,5,7,8,9,10} // [1,2,3,4,5,7,8,9,10]
또는 x := []int{} // []
– 배열의 길이를 정하지 않아도 됨.
34. 슬라이스
• 배열을 참조하는 일부를 가리킴.데이터공유
arr := []int{1,2,3,4,5}
x := arr[0:3] // 0<=i<3 [1,2,3]
x := arr[:3] // i<3 [0:3]과 동일
x := arr[3:] // i >= 3 [4,5]
• 선언
var x []float64
• 생성
x := make([]float64, 5)
x := make([]float64, 5, 10)
35. 슬라이스
• 배열을 참조하는 일부를 가리킴.데이터공유
arr := []int{1,2,3,4,5}
x := arr[0:3] // 0<=i<3 [1,2,3]
x := arr[:3] // i<3 [0:3]과 동일
x := arr[3:] // i >= 3 [4,5]
• 선언
var x []float64
• 생성
x := make([]float64, 5)
x := make([]float64, 5, 10)
37. 맵
• Key는 동등연산자(==)이 가능한 integer, float, 복소수, string,
포인터, 그리고 인터페이스와 같이 어떤 타입이든 가능
• struct와 배열,slice는 동등연산을 할 수 없기 때문에 불가.
• 사용법1
var x map[string]int
x = make(map[string]int)
x["a"]=1; x["b"]=2; x["c"]=3
• 사용법2
x := make(map[string]int)
x["a"]=1; x["b"]=2; x["c"]=3
• 사용법3
x := map[string]int{"a":1, "b":2, "c":3}
38. 맵
• 참조
name := x[”aaaa"]
또는
name, ok := x[”aaaa"]
fmt.Println(name, ok)
• 삭제
delete(x, "b")
• 갯수확인
len(x)
40. 가변함수
func add(args ...int) int {
total := 0
for _, v := range args {
total += v
}
return total
}
• add(1,2,3) OK
• xs := []int{1,2,3}
add(xs) Error. 가변인자는 슬라이스와 호환되지 않는다.
• add(xs...) OK. 가변인자 변수자체를 전달할때는 ...을 붙여야 인식됨.
가변인자는 add(foo...)와 같이 ...를 반드시 붙어야해요
41. 클로저
func main() {
add := func(x, y int) int {
return x + y
}
fmt.Println(add(1,1))
}
---------------------------------------------------------------------------------------------
func makeEvenGenerator() func() uint {
i := uint(0)
return func() (ret uint) {
ret = i
i += 2
return
}
}
func main() {
nextEven := makeEvenGenerator()
fmt.Println(nextEven()) // 0
fmt.Println(nextEven()) // 2
fmt.Println(nextEven()) // 4
}
42. Defer (지연된 호출)
• 해당함수 종료시 실행됨.
• Java의 try-finally 대체
func main() {
defer second()
first()
}
------------------------------------------------
f, _ := os.Open(filename)
defer f.Close()
• 장점
1. Close 호출을 Open 호출 가까이에 둬서 이해하기가 쉽다.
2. 함수에 return이 여러 개 있더라도 Close가 어떠한 return 시라도 호출
3. 지연된 함수는 런타임 패닉이 일어나더라도 실행
43. Panic & Recover
• Java의 throw-catch 를 대체
• panic : 런타임오류 강제발생
• recover : 런타임패닉 처리
• 잘못된 사용예. recover가 호출기도 전에 종료.
panic("PANIC")
str := recover()
• 올바른 사용예. defer와 짝을 맞춤. 익명함수 사용.
defer func() {
str := recover()
fmt.Println(str)
}()
panic("PANIC”)
• 사용목적
– 범위를 벗어난 배열 인덱스에 접근시 에러처리
– 맵을 초기화하는 것을 잊어버릴 경우 에러처리
45. 포인터
• Address 연산자로 포인터 사용
func one(xPtr *int) {
*xPtr = 0
}
func main() {
x := 5
one(&x)
fmt.Println(x) // x는 1
}
----------------------------
• new 로 포인터 사용
func main() {
xPtr := new(int)
one(xPtr)
fmt.Println(*xPtr) // x는 1
}
46. 포인터 접근
type Rectangle struct {
length, width int
}
func main() {
var r *Rectangle
r = new(Rectangle) // Rectangle에 대한 포인터 반환.
r.length = 5
(*r).length = 5 //r.length=5와 동일하다.
fmt.Println(r.length) // 5
fmt.Println((*r).length) // 5
}
• c++과 달리 -> 가 없다. 포인터, 인스턴스 모두에 대해 dot(.) 노테이션 사용
47. Struct
• Go는 클래스가 없다.
• 하지만 클래스와 동일한걸 만들수 있다.
• Java에서 Rectangle 클래스는 area()메소드를 가지고 있음
//JAVA
public class Rectangle {
private float x1, y2, x2, y2;
public float area() {
float l = distance(x1, y1, x1, y2);
float w = distance(x1, y1, x2, y1);
return l * w;
}
private float distance(float x1, float y1, float x2, float y2) {
float a = x2 - x1;
float b = y2 - xy;
return Math.sqrt(a*a + b*b);
}
}
52. Struct
• 생성방식
type Rectangle struct {
length, width int
}
var r Rectangle // Rectangle타입. 내용은 length=0, width=0
var r *Rectangle // *Rectangle타입. 내용은 nil.
r := new(Rectangle) // *Rectangle타입. 내용은 length=0, width=0
r := Rectangle{width:10, length: 50} // Rectangle타입. 이름명시
r := Rectangle{10, 50} // Rectangle타입. 순서대로 할당
53. Struct – embedded type
type Person struct {
Name string
}
• HAS-A 관계
type Android struct {
Person person
Model string
}
a.person.Name=5 //Person을 통해서 접근
• IS-A 관계
type Android struct {
Person //Android is a person
Model string
}
a := new(Android)
a.Name=5 // Android가 Person인것 처럼 접근가능.
54. Struct –기본 타입 확장
• 기존 int 타입을 기반으로 string() 함수를 붙인다.
#src/fmt/stringer_test.go 참조
type TI int
func (v TI) String() string {
return fmt.Sprintf("I: %d", int(v))
}
• Java라면
public class IntegerType extends Integer {
public String string() { .. }
}
$ javac IntegerType.java
IntegerType.java:1: error: cannot inherit from final Integer
public class IntegerType extends Integer {
^
1 error
Integer는 Final class 이므로 확장 불가.
55. Interface
• Rectangle
type Rectangle struct {
x1, y1, x2, y2 float64
}
func (r *Rectangle) area() float64 { .. }
• Circle
type Circle struct {
x, y, r float64
}
func (c *Circle) area() float64 { .. }
• Shape
type Shape interface {
area() float64
}
• 사용시
func totalArea(shapes ...Shape) float64 { .. }
어떠한 선언적 종속관계도 없다!!
57. 고루틴(go)
package main
import (
"fmt"
"math/rand"
"time"
)
func f(n int) {
amt := time.Duration(rand.Intn(250))
time.Sleep(time.Millisecond * amt)
fmt.Println(n)
}
func main() {
for i := 0; i < 1000000; i++ {
go f(i)
}
var input string
fmt.Scanln(&input)
}
58. 채널(chan)
• 채널(channel)은 두 고루틴이 서로 통신하고 실행흐름을 동기화하는 수단을
제공
func main() {
c := make(chan string)
c <- "oce”
msg := <-c
fmt.Println(msg)
}
결과
$ go run main.go
fatal error: all goroutines are asleep - deadlock!
• main함수는 첫번째 고루틴이다.
59. 채널(chan)
func main() {
c := make(chan string)
go func() { // 익명 함수의 고루틴
c <- "oce”
}()
msg := <-c
fmt.Println(msg)
}
결과
$ go run main.go
oce
• 비동기 채널설정
기본적으로 채널은 동기적. 버퍼를 주면 비동기적으로 동작가능.
c := make(chan int, 1) //길이가 1인 버퍼설정.
63. 초기화
• func init() 이 존재하면 main()보다도 먼저실행
• init()은 해당패키지 import시 실행
– import “abc” 가 실행시 abc.go내 init()이 실행된다.
• init() 여러번 중복해서 선언될수 있으며, 코드 순서대로 순차적 실행
package main
import "fmt”
var i = foo()
func foo() int {
fmt.Println("Call foo()")
return 1
}
func init() {
fmt.Println("Call init() 1")
}
func init() {
fmt.Println("Call init() 2")
}
func main() {
fmt.Println("Call main()")
}
func init() {
fmt.Println("Call init() 3")
}
실행결과
Call foo()
Call init() 1
Call init() 2
Call init() 3
Call main()
64. make()와 new()의 차이
• make()
– 오로지 slice, map, channel을 만드는 용도로만 사용.
– 포인터를 반환하지 않음. 즉 *T가 아닌 T타입을 리턴.
var p *[]int = new([]int) // slice구조를 할당함; *p == nil; 그다지 유용하지 않음
var v []int = make([]int, 100) // slice v는 이제 100개의 int를 가지는 새로운 배열을 참조함
// new : 불필요하게 복잡함:
var p *[]int = new([]int)
*p = make([]int, 100, 100)
// make: 자연스러움:
v := make([]int, 100)
65. Conversion
var f1 float64 = 6.0
f2 := 12 / f1 // 상수 12는 float64로 자동변환
2
var i int = 12
var f1 float64 = 6.0
f2 := i / f1 // 변수타입은 자동변환되지 않는다.
invalid operation: i / f1 (mismatched types int and float64)
var i = 12. //12. 은 float64 형이다.
var f1 float32 = 6.0
f2 := i / f1 //심지어 같은 float형이라도 float32와 float64는 자동형변환
불가.
invalid operation: i / f1 (mismatched types float64 and float32)
66. Conversion
var i = 12.
var f1 float32 = 6.0
f2 := i / f1
ERROR
var i = 12.
var f1 float32 = 6.0
f2 := float32(i) / f1
2
i := 12
fmt.Println(”Result = ” + i)
cannot convert "Result=" to type int
invalid operation: "Result=" + i (mismatched types string and int)
import ”strconv”
i := 12
fmt.Println("Result = " + strconv.Itoa(i))
Result = 3
67. GOROOT
• GOROOT는 Go SDK의 설치위치를 나타내며, 이 위치하위에서 기본
라이브러리와 문서등을 찾아서 사용한다.
• Go 기본설치위치
– *nix : /usr/local/go
– Windows : C:Go
• 만약 다른 곳에 설치했다면 GOROOT 환경변수를 설정해주어야함.
– ex) /application/go에 설치했다면,
export GOROOT=/application/go
export PATH=$PATH:$GOROOT/bin
– *nix계열은 .bash_profile과 같은 설정파일에 추가한다.
• 기본위치에 설치되어 있다면 GOROOT를 설정할 필요없음
68. GOPATH
• Java에는 classpath, Go에는 GOPATH
• import 시 GOPATH의 경로를 찾음
• *Nix계열은 콜론, Windows는 세미콜론으로 연결된 경로 리스트
GOPATH=/home/user/gocode
/home/user/gocode/
src/
foo/
bar/ (go code in package bar)
x.go
grep2/ (go code in package main)
y.go
bin/
grep2 (installed command)
pkg/
linux_amd64/
oce/
bar.a (installed package object)
Tip: GOPATH가 여러개일때 특정 src하위에서 install 된 패키지파일은 해당 고패스하위로 들어간다.
69. 패키지
GOPATH=<User Home Directory>/go
$ cd go
$ mkdir -p src/math2
$ cd src/math2
$ vi foo.go # 파일명과 패키지 명이 동일할 필요없음.
package math2 // 패키지명은 폴더와 이름이 일치해야함.
func Average(i, j int) float64 { // average가 아닌 대문자 Average로 선언. import후 호출가능함
return float64(i + j) / 2
}
$ go install
<User Home Directory>/go/pkg/darwin_amd64/math2.a 생성됨.
-------------------
package main
import “fmt”
import “math2”
func main() {
i := math2.Average(10,30) // 20
fmt.Println(“i=“, i)
}
> 패키지명을 math로 하면 이미 존재하는 go의 기본패키지명과 겹치므로 go install시 에러발생.
70. 패키지
• 최상위가 아닌 중간경로를 주면 math라는 이름으로 패키지 생성가능.
$ mkdir -p src/oce.org/math
$ cd src/oce.org/math
$ vi foo.go
package math
func Average(i, j int) float64 {
return float64(i + j) / 2
}
$ go install
<User Home Directory>/go/pkg/darwin_amd64/oce.org/math.a 생성됨.
-------------------
package main
import “fmt”
import “oce.org/math”
func main() {
i := math.Average(10,30) // 20
fmt.Println(“i=“, i)
}
71. 패키지
• 패키지 이름의 중복을 방지하기 위하여 import시 Alias가능
package main
import “fmt”
import “math”
import math2 “oce.org/math”
func main() {
i := math.Average(10,30)
j := math2.Average(10,30)
fmt.Println(“i=“, i, “j=“, j)
}
72. 패키지
• Alias를 Dot(.) 으로 하면 해당패키지를 이름없이 바로 접근가능.
package main
import . “fmt”
func main() {
Println(“Called without package name!”)
}
80. 문서화
• 함수정의 (src/os/exec/exec.go, src/os/exec/lp_unix.go)
func LookPath(file string) (string, error) { .. }
func (c *Cmd) Start() error { .. }
• 예제정의(src/os/exec/example_test.go)
func ExampleLookPath() {
path, err := exec.LookPath("fortune")
if err != nil {
log.Fatal("installing fortune is in your future") 이 소스가 예제항목으로 삽입된다.
}
fmt.Printf("fortune is available at %sn", path)
}
func ExampleCmd_Start() {
cmd := exec.Command("sleep", "5")
err := cmd.Start()
if err != nil {
log.Fatal(err) 이 소스가 예제항목으로 삽입된다.
}
log.Printf("Waiting for command to finish...")
err = cmd.Wait()
log.Printf("Command finished with error: %v", err)
}
81. 테스트
• 테스트 함수만드는 법
– 파일이름은 _test.go로 끝난다.
– 함수이름이 Test로 시작
– *testing.T를 인자로 받을것 (import “testing”)
• 예제
# foo_test.go
package math
import "testing"
func TestAverage(t *testing.T) {
var v float64
v = Average([]float64{1,2})
if v != 1.5 {
t.Error("Expected 1.5, got ", v)
}
}
82. 테스트
$ go test
PASS
ok oce.org/math 0.003s
• 만약 파일명이 _test.go, test.go, foo_testing.go 등 파일명규칙을 따르지 않을때는
아래와 같이 테스트파일을 못찾는다.
$ go test
? oce.org/math [no test files]
• fmt 패키지내 파일 리스트 참고 (경로 <GOROOT>/src/fmt)
doc.go
export_test.go
fmt_test.go
format.go
print.go
scan.go
scan_test.go
stringer_test.go
83. 테스트
import "testing"
type testpair struct {
values []float64
average float64
}
var tests = []testpair{
{ []float64{1,2}, 1.5 },
{ []float64{1,1,1,1,1,1}, 1 },
{ []float64{-1,1}, 0 },
}
func TestAverage(t *testing.T) {
for _, pair := range tests {
v := Average(pair.values)
if v != pair.average {
t.Error(
"For", pair.values,
"expected", pair.average,
"got", v,
)
}
}
}
struct를 이용하면 여러
테스트값을 편하게
테스트해볼 수 있어요.
86. io
• 함수정의 보다는 대부분이 interface로 구성
• 주요 인터페이스는 Reader와 Writer
• Reader는 Read(), Writer는 Write() 지원
• Reader Writer 데이터 복사
– func Copy(dst Writer, src Reader) (written int64, err error)
더 많은 정보는 여기있어요
https://golang.org/pkg/io
87. bytes
package main
import (
"bytes"
"fmt"
"os"
)
func main() {
var b bytes.Buffer // 버퍼는 초기화가 필요없다. 선언후 그대로 사용.
b.Write([]byte("Hello "))
fmt.Fprintf(&b, "world!")
b.WriteTo(os.Stdout)
}
-----
func main() {
// string 이나 []byte 를 io.Reader 로 바꿔준다.
buf := bytes.NewBufferString("R29waGVycyBydWxlIQ==")
dec := base64.NewDecoder(base64.StdEncoding, buf)
io.Copy(os.Stdout, dec)
}
더 많은 정보는 여기있어요
https://golang.org/pkg/bytes
88. os
• 파일열기 : os.Open()
• 파일닫기 : file.Close()
package main
import (
"fmt"
"os"
)
func main() {
file, err := os.Open("test.txt")
if err != nil {
// 오류를 처리
return
}
defer file.Close()
// 파일의 크기를 구함
stat, err := file.Stat()
if err != nil {
return
}
// 파일을 읽음
bs := make([]byte, stat.Size())
_, err = file.Read(bs)
if err != nil {
return
}
str := string(bs)
fmt.Println(str)
}
89. error
• 오류에 대한 내장타입
• error.New() 사용시 자체오류 생성가능
package main
import (
"errors"
"fmt"
)
func main() {
err := errors.New("emit macho dwarf: elf header corrupted")
if err != nil {
fmt.Print(err)
}
}
-----
func main() {
const name, id = "bimmler", 17
err := fmt.Errorf("user %q (id %d) not found", name, id)
if err != nil {
fmt.Print(err)
}
}
90. container
heap Package heap provides heap operations for any type that implements heap.Interface.
list Package list implements a doubly linked list.
ring Package ring implements operations on circular lists.
package main
import (
"container/list"
"fmt"
)
func main() {
// Create a new list and put some numbers in it.
l := list.New()
e4 := l.PushBack(4)
e1 := l.PushFront(1)
l.InsertBefore(3, e4)
l.InsertAfter(2, e1)
// Iterate through list and print its contents.
for e := l.Front(); e != nil; e = e.Next() {
fmt.Println(e.Value)
}
}
91. container - heap
// This example demonstrates an integer heap built using
the heap interface.
package main
import (
"container/heap"
"fmt"
)
// An IntHeap is a min-heap of ints.
type IntHeap []int
func (h IntHeap) Len() int { return len(h) }
func (h IntHeap) Less(i, j int) bool { return h[i] < h[j] }
func (h IntHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
func (h *IntHeap) Push(x interface{}) {
// Push and Pop use pointer receivers because
they modify the slice's length,
// not just its contents.
*h = append(*h, x.(int))
}
func (h *IntHeap) Pop() interface{} {
old := *h
n := len(old)
x := old[n-1]
*h = old[0 : n-1]
return x
}
// This example inserts several ints into an
IntHeap, checks the minimum,
// and removes them in order of priority.
func main() {
h := &IntHeap{2, 1, 5}
heap.Init(h)
heap.Push(h, 3)
fmt.Printf("minimum: %dn", (*h)[0])
for h.Len() > 0 {
fmt.Printf("%d ", heap.Pop(h))
}
}
92. sort
• Sort 함수는 sort.Interface가 구현된 것만 정렬가능
• sort.Interface는 Len, Less, Swap의 3개 메서드 필요.
type Interface interface {
// Len is the number of elements in the collection.
Len() int
// Less reports whether the element with
// index i should sort before the element with index j.
Less(i, j int) bool
// Swap swaps the elements with indexes i and j.
Swap(i, j int)
}
93. sort
type Person struct {
Name string
Age int
}
type ByName []Person
func (this ByName) Len() int {
return len(this)
}
func (this ByName) Less(i, j int) bool {
return this[i].Name < this[j].Name
}
func (this ByName) Swap(i, j int) {
this[i], this[j] = this[j], this[i]
}
func main() {
kids := []Person{
{"Jill",9},
{"Jack",10},
}
sort.Sort(ByName(kids))
fmt.Println(kids)
}
94. hash
type Hash interface {
// Write (via the embedded io.Writer interface) adds more data
to the running hash.
// It never returns an error.
io.Writer
// Sum appends the current hash to b and returns the resulting
slice.
// It does not change the underlying hash state.
Sum(b []byte) []byte
// Reset resets the Hash to its initial state.
Reset()
// Size returns the number of bytes Sum will return.
Size() int
// BlockSize returns the hash's underlying block size.
// The Write method must be able to accept any amount
// of data, but it may operate more efficiently if all writes
// are a multiple of the block size.
BlockSize() int
}
type Hash32 interface {
Hash
Sum32() uint32
}
type Hash64 interface {
Hash
Sum64() uint64
}
95. hash - 비암호화
• 종류 : adler32, crc32, crc64, fnv
package main
import (
"fmt"
"hash/crc32"
)
func main() {
h := crc32.NewIEEE()
h.Write([]byte("test"))
v := h.Sum32()
fmt.Println(v)
}
3632233996
97. net
• Go는 아래에 대해 Portable 인터페이스를 제공
– Network I/O
– TCP/IP
– UDP
– Domain name resolution
– Unix domain socket
type Listener interface {
// Accept waits for and returns the next connection to the listener.
Accept() (c Conn, err error)
// Close closes the listener.
// Any blocked Accept operations will be unblocked and return errors.
Close() error
// Addr returns the listener's network address.
Addr() Addr
}
98. net
//////////////////// Client 간단버전 //////////////////
conn, err := net.Dial("tcp", "google.com:80")
if err != nil {
// handle error
}
fmt.Fprintf(conn, "GET / HTTP/1.0rnrn")
status, err := bufio.NewReader(conn).ReadString('n')
// ...
////////////////// Server 간단버전 //////////////////
ln, err := net.Listen("tcp", ":8080")
if err != nil {
// handle error
}
for {
conn, err := ln.Accept()
if err != nil {
// handle error
}
go handleConnection(conn)
}
99. net
////////////// Echo 서버 ////////////
package main
import (
"io”; "log”; "net"
)
func main() {
// Listen on TCP port 2000 on all interfaces.
l, err := net.Listen("tcp", ":2000")
if err != nil {
log.Fatal(err)
}
defer l.Close()
for {
// Wait for a connection.
conn, err := l.Accept()
if err != nil {
log.Fatal(err)
}
// Handle the connection in a new
goroutine.
// The loop then returns to accepting, s
o that
// multiple connections may be served
concurrently.
go func(c net.Conn) {
// Echo all incoming data.
io.Copy(c, c)
// Shut down the connection.
c.Close()
}(conn)
}
}
$ telnet localhost 2000
I love Go 입력
I love Go 출력
101. net/rpc
package main
import (
"fmt” ; "net”; "net/rpc"
)
type Server struct {}
func (this *Server) Negate(i int64, reply *int64) error {
*reply = -i
return nil
}
func server() {
rpc.Register(new(Server))
ln, err := net.Listen("tcp", ":9999")
if err != nil {
fmt.Println(err)
return
}
for {
c, err := ln.Accept()
if err != nil {
continue
}
go rpc.ServeConn(c)
}
}
func client() {
c, err := rpc.Dial("tcp", "127.0.0.1:9999")
if err != nil {
fmt.Println(err)
return
}
var result int64
err = c.Call("Server.Negate", int64(999), &result)
if err != nil {
fmt.Println(err)
} else {
fmt.Println("Server.Negate(999) =", result)
}
}
func main() {
go server()
go client()
var input string
fmt.Scanln(&input)
}
102. flag (명령줄 파싱)
• 명령줄 플래그(-로 시작)를 flag.String(), Bool(), Int() 등을 사용하여 파싱
– flag.Int(플래그명, 기본값, 설명메시지)
– flag.IntVar(입력변수주소, 플래그명, 기본값, 설명메시지)
– 방법1
import "flag"
var ip = flag.Int("flagname", 1234, "help message for flagname”)
– 방법2
var flagvar int
func init() {
flag.IntVar(&flagvar, "flagname", 1234, "help message for flagname")
}
• 플래그가 아닌 일반파라미터는 flag.Args()를 통해 받을 수 있으며
[]string 형으로 리턴된다.
var args []string = flag.Args()
103. flag (명령줄 파싱)
package main
import (
"flag"
"fmt"
)
var species = flag.String("species", "gopher", "the species we are studying")
var gopherType string
func init() {
const (
defaultGopher = "pocket"
usage = "the variety of gopher"
)
flag.StringVar(&gopherType, "gopher_type", defaultGopher, usage)
flag.StringVar(&gopherType, "g", defaultGopher, usage+" (shorthand)")
}
func main() {
flag.Parse()
fmt.Println("species=", *species, "ngopherType=", gopherType)
var args []string = flag.Args()
fmt.Println("Args=", args)
}
104. flag (명령줄 파싱)
$ ./hello
species= gopher
gopherType= pocket
Args= []
$ ./hello -h
Usage of ./hello:
-g="pocket": the variety of gopher (shorthand)
-gopher_type="pocket": the variety of gopher
-species="gopher": the species we are studying
$ ./hello -species=oce -g=fastcat
species= oce
gopherType= fastcat
Args= []
$ ./hello -species=oce -gopher_type=fastcat 위 결과와 동일
species= oce
gopherType= fastcat
Args= []
$ ./hello -species=”oce fastcat” world war 2
species= oce fastcat
gopherType= pocket
Args= [world war 2]
105. sync
type Cond
func NewCond(l Locker) *Cond
func (c *Cond) Broadcast()
func (c *Cond) Signal()
func (c *Cond) Wait()
type Locker
type Mutex
func (m *Mutex) Lock()
func (m *Mutex) Unlock()
type Once
func (o *Once) Do(f func())
type Pool
func (p *Pool) Get() interface{}
func (p *Pool) Put(x interface{})
type RWMutex
func (rw *RWMutex) Lock()
func (rw *RWMutex) RLock()
func (rw *RWMutex) RLocker() Locker
func (rw *RWMutex) RUnlock()
func (rw *RWMutex) Unlock()
type WaitGroup
func (wg *WaitGroup) Add(delta int)
func (wg *WaitGroup) Done()
func (wg *WaitGroup) Wait()
더 많은 정보는 여기있어요
https://golang.org/pkg/sync/
106. sync/Mutex
package main
import (
"fmt”; "sync”; "time"
)
func main() {
m := new(sync.Mutex)
for i := 0; i < 10; i++ {
go func(i int) {
m.Lock()
fmt.Println(i, "start")
time.Sleep(time.Second)
fmt.Println(i, "end")
m.Unlock()
}(i)
}
var input string
fmt.Scanln(&input)
}
실행결과
0 start
0 end
1 start
1 end
2 start
2 end
3 start
3 end
4 start
4 end
5 start
5 end
6 start
6 end
7 start
7 end
8 start
8 end
9 start
9 end
107. sync/Once
package main
import (
"fmt”; "sync"
)
func main() {
var once sync.Once
onceBody := func() {
fmt.Println("Only once")
}
done := make(chan bool)
for i := 0; i < 10; i++ {
go func() {
once.Do(onceBody)
done <- true
}()
}
for i := 0; i < 10; i++ {
<-done
}
}
결과 : Only once
108. sync/WaitGroup
var wg sync.WaitGroup
var urls = []string{
"http://www.golang.org/",
"http://www.google.com/",
"http://www.somestupidname.com/",
}
for _, url := range urls {
// Increment the WaitGroup counter.
wg.Add(1)
// Launch a goroutine to fetch the URL.
go func(url string) {
// Decrement the counter when the goroutine completes.
defer wg.Done()
// Fetch the URL.
http.Get(url)
}(url)
}
// Wait for all HTTP fetches to complete.
wg.Wait()
109. Go 의 동기화 스타일
type Work struct {
x, y, z int
assigned, done bool
}
type WorkSet struct {
mu sync.Mutex
work []*Work
}
type Work struct { x, y, z int }
func worker(in <-chan *Work, out chan<- *Work) {
for w := range in {
w.z = w.x * w.y // do some work...
out <- w
}
}
func main() {
in, out := make(chan *Work), make(chan *Work)
for i := 0; i < 10; i++ { go worker(in, out) }
go sendLotsOfWork(in)
receiveLotsOfResults(out)
}
메모리공유를 통한 통신이나
공유데이터를 보호하기 위한 Lock이 필요없다.
전통적인 접근 Go 스타일
110. time
정의 : func Sleep(d Duration)
샘플 : time.Sleep(100 * time.Millisecond)
정의 : func (t Time) Sub(u Time) Duration
샘플 :
t0 := time.Now()
expensiveCall()
t1 := time.Now()
mt.Printf("The call took %v to run.n", t1.Sub(t0))
3m56s
정의 : func Date(year int, month Month, day, hour, min, sec, nsec int, loc *Location) Time
샘플 : t := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)
정의 : func (t Time) Format(layout string) string
샘플 :
const layout = "Jan 2, 2006 at 3:04pm (MST)"
t := time.Date(2009, time.November, 10, 15, 0, 0, 0, time.Local)
fmt.Println(t.Format(layout))
정의 : func Parse(layout, value string) (Time, error)
샘플 :
const longForm = "Jan 2, 2006 at 3:04pm (MST)"
t, _ := time.Parse(longForm, "Feb 3, 2013 at 7:54pm (PST)")
Go 에는 Java의 yyyyMMdd
같은 형식이 없어요.
111. regexp
정의 : func MatchString(pattern string, s string) (matched bool, err error)
샘플 : matched, err := regexp.MatchString("foo.*", "seafood")
정의 : func MustCompile(str string) *Regexp
샘플 : var re = regexp.MustCompile(`^[a-z]+[[0-9]+]$`)
정의 : func (re *Regexp) MatchString(s string) bool
샘플 : fmt.Println(re.MatchString("adam[23]"))
정의 : func (re *Regexp) FindAllString(s string, n int) []string
샘플 : fmt.Println(re.FindAllString("paranormal", -1))
정의 : func (re *Regexp) ReplaceAllString(src, repl string) string
샘플 : fmt.Println(re.ReplaceAllString("-ab-axxb-", "T"))
112. database
age := 27
rows, err := db.Query("SELECT name FROM users WHERE age=?", age)
if err != nil {
log.Fatal(err)
}
defer rows.Close()
for rows.Next() {
var name string
if err := rows.Scan(&name); err != nil {
log.Fatal(err)
}
fmt.Printf("%s is %dn", name, age)
}
if err := rows.Err(); err != nil {
log.Fatal(err)
}
https://github.com/golang/go/wiki/SQLDrivers
113. database - drivers
• MySQL: https://github.com/ziutek/mymysql [*]
• MySQL: https://github.com/go-sql-driver/mysql/ [*]
• Postgres (pure Go): https://github.com/lib/pq [*]
• Oracle: https://github.com/mattn/go-oci8
• MS SQL Server (pure go): https://github.com/denisenkom/go-mssqldb
그 외의 드라이버는 여기를 참조하세요.
https://github.com/golang/go/wiki/SQLDrivers
114. database - mysql
package main
import (
"os"
"github.com/ziutek/mymysql/mysql"
_ "github.com/ziutek/mymysql/native" // Native
engine
// _ "github.com/ziutek/mymysql/thrsafe" //
Thread safe engine
)
func main() {
db := mysql.New("tcp", "", "127.0.0.1:3306", user,
pass, dbname)
err := db.Connect()
if err != nil {
panic(err)
}
rows, res, err := db.Query("select * from X where
id > %d", 20)
if err != nil {
panic(err)
}
https://github.com/ziutek/mymysql
for _, row := range rows {
for _, col := range row {
if col == nil {
// col has NULL value
} else {
// Do something with text in col (type
[]byte)
}
}
// You can get specific value from a row
val1 := row[1].([]byte)
// You can use it directly if conversion isn't
needed
os.Stdout.Write(val1)
// You can get converted value
number := row.Int(0) // Zero value
str := row.Str(1) // First value
bignum := row.MustUint(2) // Second value
// You may get values by column name
first := res.Map("FirstColumn")
second := res.Map("SecondColumn")
val1, val2 := row.Int(first), row.Str(second)
}
}