Go 언어 빠르게 훑어보기
기본 문법
기본 구조
| package main |
| |
| import "fmt" |
| |
| func main() { |
| fmt.Println("Hello Go") |
| } |
$ go run hello.go
선언
| var foo int |
| var foo int = 42 |
| var foo, bar int = 42, 1302 |
| var foo = 42 |
| foo := 42 |
| const constant = "This is a constant" |
함수
| |
| func functionName() {} |
| |
| |
| func functionName(param1 string, param2 int) {} |
| |
| |
| func functionName(param1, param2 int) {} |
| |
| |
| func functionName() int { |
| return 42 |
| } |
| |
| |
| func returnMulti() (int, string) { |
| return 42, "foobar" |
| } |
| var x, str = returnMulti() |
| |
| |
| func returnMulti2() (n int, s string) { |
| n = 42 |
| s = "foobar" |
| |
| return |
| } |
| var x, str = returnMulti2() |
type 종류 (Built-in)
| bool |
| |
| string |
| |
| int int8 int16 int32 int64 |
| uint uint8 uint16 uint32 uint64 uintptr |
| |
| byte |
| |
| rune |
| |
| float32 float64 |
| |
| complex64 complex128 |
기타 if문, for문, array, map 등은 약간의 문법만 차이가 있을 뿐 java나 다른 언어와 비슷하다고 느꼈기 때문에 생략한다.
Struct
go 언어는 클래스가 없고 struct만 있다. struct안에는 멤버 변수가 들어갈 수 있고 struct의 멤버 함수 처럼 쓸 수 있는 Method
나 Pointer Receiver
가 있다.
| |
| type Vertex struct { |
| X, Y int |
| } |
| |
| var v = Vertex{1, 2} |
| var v = Vertex{X: 1, Y: 2} |
| var v = []Vertex{{1,2},{5,2},{5,5}} |
| |
| |
| v.X = 4 |
| |
| |
| |
| func (v Vertex) Abs() float64 { |
| return math.Sqrt(v.X*v.X + v.Y*v.Y) |
| } |
| |
| |
| v.Abs() |
| |
| |
| func (v *Vertex) add(n float64) { |
| v.X += n |
| v.Y += n |
| } |
이때, struct에는 자바와 같이 상속에 대한 직접적인 키워드는 없지만, struct내에 Embedding을 이용할수는 있다.
| |
| type Server struct { |
| Host string |
| Port int |
| *log.Logger |
| } |
| |
| |
| server := &Server{"localhost", 80, log.New(...)} |
| |
| |
| server.Log(...) |
| |
| |
| var logger *log.Logger = server.Logger |
Interface
struct가 데이터의 집합이라면 interface는 메소드의 집합이다. struct와 마찬가지로 Embedding을 이용할 수 있다. 이런 특징 때문에 Go에서는 주로 작은 인터페이스를 이용하는 것이 권장된다고 한다.
| type Reader interface { |
| Read(p []byte) (n int, err error) |
| } |
| |
| type Writer interface { |
| Write(p []byte) (n int, err error) |
| } |
| |
| |
| type ReadWriter interface { |
| Reader |
| Writer |
| } |
Error
go에는 Exception Handler이 없다. 대신 오류를 생성할 수 있는 함수는 tyope의 추가 반환 값만 선언하면 error가 된다.
| |
| |
| type error interface { |
| Error() string |
| } |
| func sqrt(x float64) (float64, error) { |
| if x < 0 { |
| return 0, errors.New("negative value") |
| } |
| return math.Sqrt(x), nil |
| } |
| |
| func main() { |
| val, err := sqrt(-1) |
| if err != nil { |
| |
| fmt.Println(err) |
| return |
| } |
| |
| fmt.Println(val) |
| } |
Concurrency
Goroutine
고루틴은 경량 스레드이다. (OS 스레드가 아닌 Go에서 관리).
go f(a, b)실행되는 새로운 고루틴을 시작한다.
| |
| func doStuff(s string) { |
| } |
| |
| func main() { |
| |
| go doStuff("foobar") |
| |
| |
| go func (x int) { |
| |
| }(42) |
| } |
Channel
채널은 고루틴 간의 Synchronous를 처리하기 위한 방법이다. 고루틴끼리 데이터를 주고받는 통로라고 볼 수 있다. 채널은 make(자료형 미리 명시) 함수를 통해 미리 생성되어야 하고, 채널 연산자 <-를 통해 데이터를 주고 받는다. 채널은 Goroutine 사이에서 데이터를 주고 받는데 사용되는데 상대편이 준비될 때까지 채널에서 대기함으로써 별도의 lock을 걸지 않고 데이터를 동기화하는데 사용된다.
| ch := make(chan int) |
| ch <- 42 |
| v := <-ch |
| |
| |
| |
| |
| ch := make(chan int, 100) |
| |
| close(ch) |
| |
| |
| v, ok := <-ch |
| |
| |
| |
| |
| for i := range ch { |
| fmt.Println(i) |
| } |
| |
| |
| func doStuff(channelOut, channelIn chan int) { |
| select { |
| case channelOut <- 42: |
| fmt.Println("We could write to channelOut!") |
| case x := <- channelIn: |
| fmt.Println("We could read from channelIn") |
| case <-time.After(time.Second * 1): |
| fmt.Println("timeout") |
| } |
| } |
참고자료