let's go (golang)

117
Lets Go 2015-3-14 송상욱 swsong at fastcatsearch.com

Upload: -

Post on 15-Jul-2015

4.941 views

Category:

Technology


455 download

TRANSCRIPT

Page 1: Let's Go (golang)

Let’s Go

2015-3-14

송상욱swsong at fastcatsearch.com

♥ ♥

Page 2: Let's Go (golang)

Why Go?

• 클라우드 시스템 관련 Core들이 Go로 작성되고 있음.

• 특히 Docker는 Go의 성공사례

• 기존 PaaS를 분석하려고 하니 Go를 읽을 줄 알아야한다.

• Github의 Go 프로젝트 59,145개 (2015.3.14기준)

Page 3: Let's Go (golang)

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 기준으로 뽑아봤어요

Page 4: Let's Go (golang)

참고문서

• golang-korea

– go 개발언어 관련 자료를 한국어로 번역하는 프로젝트

– https://code.google.com/p/golang-korea/

• 그외의 인터넷 문서들

Page 5: Let's Go (golang)

기초

형아들~♥ 이제 부터 나의 기초를 보여줄게

난 생긴것 처럼 단순한 아이야~ ♥

자 그럼 Let’s Go~♥

Page 6: Let's Go (golang)

Go 는 Object-Oriented 언어인가?• 맞기도 하고 아니기도 하다.

– http://golang.org/doc/faq#Is_Go_an_object-oriented_language

• 아닌 이유– 상속관계가 없다. No subclass

• 맞는 이유– object-oriented 스타일의 프로그래밍을 허용한다. interface제공.

• object-oriented 스타일의 프로그래밍?– 상속은 제공하지 않으며 interface만 제공.

– implements"라는 선언 필요없음.

– 단순히 해당 인터페이스의 메소드를 구현하기만 하면 인터페이스 사용가능

Page 7: Let's Go (golang)

준비사항

• 홈페이지 : http://golang.org/

• Go SDK 다운로드 : http://golang.org/dl/

• 편집도구 : LiteIDE

– 다운로드 :http://sourceforge.net/projects/liteide/files/

Page 8: Let's Go (golang)

함수형태• 리턴값 없음

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

}

리시버는나중에자세하게나오니까 염려하지마요

Page 9: Let's Go (golang)

Go 가시성

• 최상위 type, 함수, method, 상수, 변수 혹은 구조체의필드나 method의 이름이 대문자로 시작하면 패키지의사용자는 접근이 가능

• 반면에 소문자일 경우에는 패키지 내부에서만 접근이가능

Page 10: Let's Go (golang)

진입점

• main 패키지의 main() 함수

package mainfunc main() {

//무언가를 수행한다.}

Page 11: Let's Go (golang)

실행과 빌드

• 실행$ go run 파일명

• 빌드$ go build또는$ go build 파일명

• 빌드결과삭제$ go clean

Page 12: Let's Go (golang)

숫자타입

• 정수형– uint8, uint16, uint32, uint64

– int8, int16, int32, int64

– uint, int, uintptr : 장비의존적

– uint8 == byte

– uint32 == rune

• 부동소숫점– float32, float64

• 복소수– complex64, complex128

Page 13: Let's Go (golang)

그외 모든 타입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

Page 14: Let's Go (golang)

키워드

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

Page 15: Let's Go (golang)

Java와 다른점 몇가지• 세미콜론은 생략한다. 하지만 같은줄에 여러명령에는 사용.

a= 1b= 2c=1; d=2

• 변수선언에는 var를 사용하고 타입은 맨뒤에 선언var a int cf) int avar 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 과 동일.

Page 16: Let's Go (golang)

Java와 다른점 몇가지 2• switch-case 는 break가필요없다. 기본이 break이며, 필요시 fallthrough 사용.• try-catch-finally, throw가없다.

defer finallyraise throwrecover catch

• 포인터존재var a *Humana := 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 publicvar price int privatefunc CallMePublic() publicfunc callMeInside() private

Page 17: Let's Go (golang)

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 intb string)

import (“fmt”“io”)

Page 18: Let's Go (golang)

변수선언/할당

• 사용법1var x string = "Hello World"

• 사용법2var x stringx = "Hello World"

• 사용법3x := "Hello World"> 일반적으로 많이 사용하는 방식. 타입추정.

Page 19: Let's Go (golang)

변수선언/할당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.)

}

Page 20: Let's Go (golang)

다중값 할당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 사용.

Page 21: Let's Go (golang)

다중값 할당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

Page 22: Let's Go (golang)

다중값 할당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

Page 23: Let's Go (golang)

사용하지 않는 변수

• Go 컴파일러는 사용하지 않는 변수존재시에러발생.

func main() {

i := 0

}

$ go run test.go

# command-line-arguments

.\test.go:16: i declared and not used

Page 24: Let's Go (golang)

문자열 비교

• 자바와 다른점

var x string = "hello"

var y string = "hello"

fmt.Println(x == y)

> true

Page 25: Let's Go (golang)

상수

• 변수

var x string = "Hello World”

• 상수

const x string = "Hello World"

Page 26: Let's Go (golang)

상수• 상수의 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

)

Page 27: Let's Go (golang)

다중 정의• 변수

var (

a = 5

b = 10

)

• 상수const (

Space = " ”

Newline = "\n"

)

Page 28: Let's Go (golang)

다중 정의• Import

import (

"os"

"fmt"

)

• Typetype(

book struct {

title string

price int

}

coffee struct {

size int

origin string

}

)

Page 29: Let's Go (golang)

루프

• For가 유일한 루프.

• 괄호가 없다.

– 사용법1

for { }

– 사용법2

for i < 10 { }

– 사용법3

for i:=0 ; i < 10; i++ { }

Page 30: Let's Go (golang)

특별 루프

• Rangefunc 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 usedfunc main() {

x := [5]int{1,2,3,4}

for _, value := range x {

fmt.Println(value)

}

}– _(언더스코어)는 컴파일러에게이것이 필요하지 않다고 알려주는 데 사용

Page 31: Let's Go (golang)

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")}

Page 32: Let's Go (golang)

Switch-Case• 컴마로 여러 조건가능.

switch c {

case ' ', '?', '&', '=', '#', '+', '%':

}

Page 33: Let's Go (golang)

배열• 사용법1

var x [5]intx[0] = 1; x[1] = 2; ;x[2] = 3; x[3] = 4; x[4] = 5

• 사용법2x := [5]int{1,2,3,4,5}

• 사용법3x := [5]int{

1,2,3,4,5,

}– 한줄씩 사용할 경우 컴마가 반드시 값뒤에 붙어야하고, 마지막 원소도

반드시 컴마존재.

• 사용법4x := []int{1,2,3,4,5,7,8,9,10} // [1,2,3,4,5,7,8,9,10]또는 x := []int{} // []– 배열의 길이를 정하지 않아도 됨.

Page 34: Let's Go (golang)

슬라이스

• 배열을 참조하는 일부를 가리킴.데이터공유

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)

Page 35: Let's Go (golang)

슬라이스

• 배열을 참조하는 일부를 가리킴.데이터공유

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)

Page 36: Let's Go (golang)

슬라이스 관련함수

• appendslice1 := []int{1,2,3}

slice2 := append(slice1, 4, 5) // 4,5 를 추가.

// slice1 [1,2,3]

// slice2 [1,2,3,4,5]

• copyslice1 := []int{1,2,3}

slice2 := make([]int, 2) // 길이가 2인 슬라이스

copy(slice2, slice1)

// slice1 [1,2,3]

// slice2 [1,2]

Page 37: Let's Go (golang)

맵• Key는 동등연산자(==)이 가능한 integer, float, 복소수, string,

포인터, 그리고 인터페이스와 같이 어떤 타입이든 가능

• struct와 배열,slice는 동등연산을 할 수 없기 때문에 불가.

• 사용법1var x map[string]int

x = make(map[string]int)

x["a"]=1; x["b"]=2; x["c"]=3

• 사용법2x := make(map[string]int)

x["a"]=1; x["b"]=2; x["c"]=3

• 사용법3x := map[string]int{"a":1, "b":2, "c":3}

Page 38: Let's Go (golang)

• 참조name := x[”aaaa"]

또는

name, ok := x[”aaaa"]

fmt.Println(name, ok)

• 삭제delete(x, "b")

• 갯수확인len(x)

Page 39: Let's Go (golang)

다중맵elements := map[string]map[string]string{

"H": map[string]string{

"name":"Hydrogen",

"state":"gas",

},

"He": map[string]string{

"name":"Helium",

"state":"gas",

},

}

Page 40: Let's Go (golang)

가변함수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...)와같이 ...를반드시 붙어야해요

Page 41: Let's Go (golang)

클로저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 = ii += 2return

}}func main() {

nextEven := makeEvenGenerator()fmt.Println(nextEven()) // 0fmt.Println(nextEven()) // 2fmt.Println(nextEven()) // 4

}

Page 42: Let's Go (golang)

Defer (지연된 호출)• 해당함수 종료시 실행됨.

• Java의 try-finally 대체

func main() {

defer second()

first()

}

------------------------------------------------

f, _ := os.Open(filename)

defer f.Close()

• 장점

1. Close 호출을 Open 호출 가까이에 둬서 이해하기가 쉽다.

2. 함수에 return이 여러 개 있더라도 Close가 어떠한 return 시라도 호출

3. 지연된 함수는 런타임 패닉이 일어나더라도 실행

Page 43: Let's Go (golang)

Panic & Recover• Java의 throw-catch 를 대체• panic : 런타임오류 강제발생• recover : 런타임패닉 처리

• 잘못된 사용예. recover가호출기도 전에 종료.panic("PANIC")str := recover()

• 올바른 사용예. defer와 짝을 맞춤. 익명함수 사용.defer func() {

str := recover()fmt.Println(str)

}()panic("PANIC”)

• 사용목적– 범위를 벗어난 배열 인덱스에 접근시 에러처리– 맵을 초기화하는 것을 잊어버릴 경우 에러처리

Page 44: Let's Go (golang)

구조체 / 인터페이스

Page 45: Let's Go (golang)

포인터• 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

}

Page 46: Let's Go (golang)

포인터 접근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(.) 노테이션 사용

Page 47: Let's Go (golang)

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);

}

}

Page 48: Let's Go (golang)

Struct//C++

class rectangle {

private:

float x1, y2, x2, y2;

public:

float area(void);

}

inline float rectangle::area()

{

float l = distance(x1, y1, x1, y2);

float w = distance(x1, y1, x2, y1);

return l * w;

}

float distance(float x1, float y1, float x2, float y2)

{

float a = x2 - x1;

float b = y2 - xy;

return sqrt(a*a + b*b);

}

Page 49: Let's Go (golang)

Struct• Receiver를 사용하여 특정 type에 종속적 함수를 생성한다.

//Go

type Rectangle struct {

x1, y1, x2, y2 float64

}

func (r *Rectangle) area() float64 {

l := distance(r.x1, r.y1, r.x1, r.y2)

w := distance(r.x1, r.y1, r.x2, r.y1)

return l * w

}

func distance(x1, y1, x2, y2 float64) float64 {

a := x2 – x1

b := y2 – y1

return math.Sqrt(a*a + b*b)

}

func main() {

r := Rectangle{1, 5, 3, 7}

fmt.Println(r) // {1 5 3 7}

}

Page 50: Let's Go (golang)

Struct• 리시버는 포인터 or 객체중 어느걸 써야할까?

type Rectangle struct {

length, width int

}

func (r Rectangle) set(i, j int) {

r.length = i

r.width = j

}

-----

• Receiver는 아래 두가지 모두 사용가능.

func (r Rectangle) set(i, j int) { .. } // OK

func (r *Rectangle) set(i, j int) { .. } // OK

Page 51: Let's Go (golang)

Struct1. 객체 사용시

func (r Rectangle) set(i, j int) {

r.length = i

r.width = j

}

func main() {

r := Rectangle{1, 5}

r.set(10, 50)

fmt.Println(r) // [1 5] 안바뀐다. r이 set함수에 복사되어 전달됨. shallow copy.

}

2. 포인터 사용시

func (r *Rectangle) set(i, j int) { ..}

결과 [10 50]

변경됨. call by reference.

Page 52: Let's Go (golang)

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타입. 순서대로 할당

Page 53: Let's Go (golang)

Struct – embedded typetype 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인것 처럼 접근가능.

Page 54: Let's Go (golang)

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 이므로 확장 불가.

Page 55: Let's Go (golang)

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 { .. }

어떠한 선언적 종속관계도 없다!!

Page 56: Let's Go (golang)

동시성

Page 57: Let's Go (golang)

고루틴(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 stringfmt.Scanln(&input)

}

Page 58: Let's Go (golang)

채널(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함수는 첫번째 고루틴이다.

Page 59: Let's Go (golang)

채널(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인 버퍼설정.

Page 60: Let's Go (golang)

채널(chan) - 방향• 양방향

func f(c chan string)

• 입력전용

func f(c chan<- string)

• 출력전용

func f(c <-chan string)

Page 61: Let's Go (golang)

Selectc1 := make(chan string)

c2 := make(chan string)

select {

case msg1 := <- c1:

fmt.Println("Message 1", msg1)

case msg2 := <- c2:

fmt.Println("Message 2", msg2)

case <- time.After(time.Second):

fmt.Println("timeout")

default:

fmt.Println("nothing ready")

}

Page 62: Let's Go (golang)

기타

Page 63: Let's Go (golang)

초기화• 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() 1Call init() 2Call init() 3Call main()

Page 64: Let's Go (golang)

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)

Page 65: Let's Go (golang)

Conversionvar 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)

Page 66: Let's Go (golang)

Conversionvar 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

Page 67: Let's Go (golang)

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를 설정할 필요없음

Page 68: Let's Go (golang)

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.gogrep2/ (go code in package main)

y.gobin/

grep2 (installed command)pkg/

linux_amd64/oce/

bar.a (installed package object)

Tip: GOPATH가 여러개일때 특정 src하위에서 install 된 패키지파일은 해당 고패스하위로 들어간다.

Page 69: Let's Go (golang)

패키지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 mainimport “fmt”import “math2”func main() {

i := math2.Average(10,30) // 20fmt.Println(“i=“, i)

}> 패키지명을 math로하면 이미 존재하는 go의 기본패키지명과 겹치므로 go install시 에러발생.

Page 70: Let's Go (golang)

패키지• 최상위가 아닌 중간경로를 주면 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)

}

Page 71: Let's Go (golang)

패키지• 패키지 이름의 중복을 방지하기 위하여 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)

}

Page 72: Let's Go (golang)

패키지• Alias를 Dot(.) 으로 하면 해당패키지를 이름없이 바로 접근가능.

package main

import . “fmt”

func main() {

Println(“Called without package name!”)

}

Page 73: Let's Go (golang)

패키지 - remote

• go get

Page 74: Let's Go (golang)

문서화• Java에는 javadoc, Go에는 godoc• usage: godoc package [name ...]

godoc -http=:6060

$ godoc oce.org/mathPACKAGE DOCUMENTATION

package mathimport "oce.org/math”

FUNCTIONS

func Average(i, j int) float64

$ godoc oce.org/math average 대소문자구분No match found.

$ godoc oce.org/math Averagefunc Average(i, j int) float64

$godoc –http=:6060 로컬 웹서버시작 http://localhost:6060/pkg/

Page 75: Let's Go (golang)

문서화//Copyright 2015

// oce.org에서 제공하는 수학패키지.

// 빈줄삽입.

// 2015-3-14 업데이트.

package math

// 평균을 구한다.

// 입력값은 i,j 정수를 받아들인다.

// 리턴값은 float64이다.

//

// 입력값:

// i 첫번째정수 Tab을 넣었다.

// j 두번째정수 Tab을 넣었다.

func Average(i, j int) float64 {

return float64(i + j) / 2

}

주석에 Tab이 들어있으면, 회색Box안으로표시되요

Page 76: Let's Go (golang)

문서화$ go install; godoc oce.org/math

PACKAGE DOCUMENTATION

package math

import "oce.org/math"

oce.org에서 제공하는 수학패키지.

빈줄이 나타났다.

2015-3-14 업데이트.

FUNCTIONS

func Average(i, j int) float64

평균을 구한다. 입력값은 i,j 정수를 받아들인다. 리턴값은 float64이다. 주석내 개행은무시된다.

입력값:

i 첫번째정수

j 두번째정수

Page 77: Let's Go (golang)

문서화

http://localhost:6060/pkg

$ godoc -http=:6060

Page 78: Let's Go (golang)

문서화http://localhost:6060/pkg/oce.org/math/$ godoc -http=:6060

가장좋은 문서화예제는 Go

sdk의 소스에있어요.

<GOROOT>/src/fmt/print.go

<GOROOT>/src/fmt/doc.go

를 참조하세요.

Page 79: Let's Go (golang)

문서화

• Example 도 넣을수 있다.

패키지 os/exec/

Page 80: Let's Go (golang)

문서화• 함수정의 (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 %s\n", 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)

}

Page 81: Let's Go (golang)

테스트• 테스트 함수만드는 법

– 파일이름은 _test.go로끝난다.

– 함수이름이 Test로 시작

– *testing.T를인자로 받을것 (import “testing”)

• 예제# foo_test.gopackage math

import "testing"

func TestAverage(t *testing.T) {var v float64v = Average([]float64{1,2})if v != 1.5 {

t.Error("Expected 1.5, got ", v)}

}

Page 82: Let's Go (golang)

테스트$ 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

Page 83: Let's Go (golang)

테스트import "testing"

type testpair struct {values []float64average 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를 이용하면 여러

테스트값을편하게

테스트해볼수 있어요.

Page 84: Let's Go (golang)

핵심패키지

Page 85: Let's Go (golang)

stringsstrings.Contains("test", "es") // true

strings.Count("test", "t") // 2

strings.HasPrefix("test", "te") // true

strings.HasSuffix("test", "st") // true

strings.Index("test", "e") // 1

strings.Join([]string{"a","b"}, "-") // "a-b"

strings.Repeat("a", 5) // "aaaaa"

strings.Replace("aaaa", "a", "b", 2) // "bbaa"

strings.Split("a-b-c-d-e", "-") // []string{"a","b","c","d","e"}

strings.ToLower("TEST") // "test"

strings.ToUpper("test") // "TEST”

----

arr := []byte("test")

str := string([]byte{'t','e','s','t'})

더 많은 정보는 여기있어요https://golang.org/pkg/strings

Page 86: Let's Go (golang)

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

Page 87: Let's Go (golang)

bytespackage 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

Page 88: Let's Go (golang)

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)

}

Page 89: Let's Go (golang)

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", 17err := fmt.Errorf("user %q (id %d) not found", name, id)if err != nil {

fmt.Print(err)}

}

Page 90: Let's Go (golang)

containerheap 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)}

}

Page 91: Let's Go (golang)

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 := *hn := 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: %d\n", (*h)[0])for h.Len() > 0 {

fmt.Printf("%d ", heap.Pop(h))}

}

Page 92: Let's Go (golang)

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)

}

Page 93: Let's Go (golang)

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)

}

Page 94: Let's Go (golang)

hashtype 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 {HashSum32() uint32

}

type Hash64 interface {HashSum64() uint64

}

Page 95: Let's Go (golang)

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

Page 96: Let's Go (golang)

crypto – 암호화해시• 종류 : aes, cipher, des, dsa, ecdsa, elliptic, hmac, md5, rand, rc4, rsa, sha1,

sha256, sha512, subtle, tls, 509

package main

import ("crypto/sha1""fmt""io"

)

func main() {h := sha1.New()io.WriteString(h, "His money is twice tainted:")io.WriteString(h, " 'taint yours and 'taint mine.")fmt.Printf("% x", h.Sum(nil))

}

Page 97: Let's Go (golang)

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

}

Page 98: Let's Go (golang)

net//////////////////// Client 간단버전 //////////////////conn, err := net.Dial("tcp", "google.com:80")if err != nil {

// handle error}fmt.Fprintf(conn, "GET / HTTP/1.0\r\n\r\n")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)

}

Page 99: Let's Go (golang)

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, so 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 2000I love Go 입력I love Go 출력

Page 100: Let's Go (golang)

net/httppackage main

import ("net/http" ; "io")

func hello(res http.ResponseWriter, req*http.Request) {

res.Header().Set("Content-Type","text/html",

)io.WriteString(

res,`<doctype html>

<html><head><title>Hello World</title></head><body>Hello World!</body>

</html>`,)

}

func main() {http.HandleFunc("/hello", hello)http.ListenAndServe(":9000", nil)

}

http://localhost:9000/hello

HandleFunc는 URL 라우팅(/hello)처리를담당해요

Page 101: Let's Go (golang)

net/rpcpackage 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)

}

Page 102: Let's Go (golang)

flag (명령줄 파싱)• 명령줄 플래그(-로 시작)를 flag.String(), Bool(), Int() 등을 사용하여 파싱

– flag.Int(플래그명, 기본값, 설명메시지)

– flag.IntVar(입력변수주소, 플래그명, 기본값, 설명메시지)

– 방법1import "flag"

var ip = flag.Int("flagname", 1234, "help message for flagname”)

– 방법2var flagvar int

func init() {

flag.IntVar(&flagvar, "flagname", 1234, "help message for flagname")

}

• 플래그가 아닌 일반파라미터는 flag.Args()를 통해 받을 수 있으며[]string 형으로 리턴된다.

var args []string = flag.Args()

Page 103: Let's Go (golang)

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)

}

Page 104: Let's Go (golang)

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]

Page 105: Let's Go (golang)

synctype 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/

Page 106: Let's Go (golang)

sync/Mutexpackage 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 start0 end1 start1 end2 start2 end3 start3 end4 start4 end5 start5 end6 start6 end7 start7 end8 start8 end9 start9 end

Page 107: Let's Go (golang)

sync/Oncepackage 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

Page 108: Let's Go (golang)

sync/WaitGroupvar 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()

Page 109: Let's Go (golang)

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 스타일

Page 110: Let's Go (golang)

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같은 형식이 없어요.

Page 111: Let's Go (golang)

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"))

Page 112: Let's Go (golang)

databaseage := 27rows, err := db.Query("SELECT name FROM users WHERE age=?", age)if err != nil {

log.Fatal(err)}defer rows.Close()for rows.Next() {

var name stringif err := rows.Scan(&name); err != nil {

log.Fatal(err)}fmt.Printf("%s is %d\n", name, age)

}if err := rows.Err(); err != nil {

log.Fatal(err)}

https://github.com/golang/go/wiki/SQLDrivers

Page 113: Let's Go (golang)

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

Page 114: Let's Go (golang)

database - mysqlpackage 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 rowval1 := row[1].([]byte)

// You can use it directly if conversion isn't needed

os.Stdout.Write(val1)

// You can get converted valuenumber := row.Int(0) // Zero valuestr := row.Str(1) // First valuebignum := row.MustUint(2) // Second value

// You may get values by column namefirst := res.Map("FirstColumn")second := res.Map("SecondColumn")val1, val2 := row.Int(first), row.Str(second)

}}

Page 115: Let's Go (golang)

logpackage main

import (

"bytes"

"fmt"

"log"

)

func main() {

var buf bytes.Buffer

logger := log.New(&buf, "logger: ", log.Lshortfile)

logger.Print("Hello, log file!")

fmt.Print(&buf)

}

logger: main.go:12: Hello, log file!

Page 116: Let's Go (golang)

log - level• 로그레벨에 따라 로깅하는 패키지는 기본 SDK에 없다.

• https://github.com/jcelliott/lumber

• 콘솔로거

log := lumber.NewConsoleLogger(lumber.WARN)

• 파일로거

log := lumber.NewFileLogger("filename.log", lumber.INFO, lumber.ROTATE, 5000, 9, 100)

• 파일로거 (rotate)

log := lumber.NewRotateLogger("filename.log", 5000, 9)

• 사용법

log.Trace("the %s log level", "lowest")

log.Debug("")

log.Info("the default log level")

log.Warn("")

log.Error("")

log.Fatal("the %s log level", "highest")

• 로그앞에 prefix 붙이기

log.Prefix("MYAPP")

Page 117: Let's Go (golang)

수고하셨어요~♥