[컴][go] Go 문법 간단 정리

golang syntax / go 언어 / golang cheat sheet / golang 문법

go 문법

import 문법

import "fmt"

또는

import (
    "fmt"
    "math"
)

함수선언


func add(x int, y int) int {
    return x + y
}

또는

func add(x, y int) int {
    return x + y
}

여러개 return
func add(x, y int) (int, int) {
    return x, y
}

return 에 이름 붙이기(알아서 x, y 가 return 됨)
func add(x, y int) (x, y int) {
    x = x + 1
    y = y + 1
    return
}

// func(int) int 를 return 하는 함수 adder()
func adder() func(int) int {
    sum := 0
    return func(x int) int {
        sum += x
        return sum
    }
}


변수선언

const (
  cc1 = "hello"
  cc2 = "babo"
)
var x, y, z int
var a, b, c int = 1, 2, 3
var p, j bool
var k, l = true, "no"

type Pointer struct {
    X, Y int
}


func main() {
   
    aa, bb := true, "hello!"   // 함수내에서만 가능
    const gogolang = "gogo"
    fmt.Println(a, b, c, x, y, z, p, j)

    // 배열, slice 라 부른다.
    p := []int{2, 3, 5, 7, 11, 13}
    fmt.Println(p[0])
    
    fmt.Println("p[1:4] ==", p[1:4])
    fmt.Println("p[:3] ==", p[:3])
    fmt.Println("p[4:] ==", p[4:])
   
    // 배열 생성, '0' 으로 초기화된다.
    arr := make([]int, 5)  // len(arr)=5, array item 은 int type
    arr2 := make([]int, 0, 5) // len(b)=0, cap(b)=5  , 용량제한


    //
    //
    var m map[string]Pointer
    m = make(map[string]Pointer)

    m["1stPointer"] = Pointer{ 0, 1}
    fmt.Println(m["1stPointer"])

    //
    //
    var mm = map[string]Pointer{
      "1stP": Pointer{0,1},
      "2ndP": {2,3},
    }

    // 
    m2 := make(map[string]int)
    m2["mykey"] = 48
    delete(m2, "mykey")
    v, ok := m2["mykey"]   // mykey 가 존재하면 ok 는 true, 존재하지 않으면 ok 는 false


}

  

}

slice 참고 자료


make 함수

type Job func()
jobQueue := make(chan Job, 10) // buffer 가 10 인 channel 만들기
jobQueue := make([]Job, 10) // Job 10개가 들어가는 array  만들기
r := make(<-chan bool)          // 읽기 전용 채널
w := make(chan<- []os.FileInfo) // 쓰기 전용 채널
// a channel which:
//  - you can only write to
//  - holds another channel as its value
c := make(chan<- chan bool) // 아래 "channel 관련" 을 참고하자.


slice / map /chan 을 new 할때 쓴다. slice, map, chan 에 사용할 때, 각각 다른 방식으로 동작한다.

이 녀석이 allocate 하고, initialize 를 해준다. 참고로, 이 make 를 써야하는 slice/map/chan 은 선언(declare) 만 해서는 reference 만 생성된다. 그러니 struct 안에넣을 때는 make() 를 호출 해주는 init 함수등이 따로 필요하다.





channel


ready := make(chan bool)

위와 같은 unbuffered channel은 sender 나 receiver 가 준비가 돼서 communicate 가 될 때까지 block 된다. 그러므로, 이 녀석은 필연적으로 goroutine 과 함께 써야 한다. 왜냐하면, 만약 이 channel 에 대해 read 를 시도하면, 일단 block 되어 버리는데, 이상태에서 이 channel 에 write 를 해줄 방법은 goroutine 등 다른 thread 를 사용하는 수밖에 없기 때문이다.



cap()

len() 은 data 가 얼마나 존재하는지 알려주고, cap() 이라는 것은 array 가 있으면 이 array 가 할당해 놓은 memory size 를 이야기한다.



nil

None,  null 같은 개념이다.


error type


type error interface {
    Error() string
}

errors.New 로 error type 의 string 을 만들 수 있다.
func Sqrt(f float64) (float64, error) {
    if f < 0 {
        return 0, errors.New("math: square root of negative number")
    }
    // implementation
}



for 문


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

// 
j := 0 
for j < 10 {
    sum += j
}

// 
for{
  if j < 10 {
     sum += j
  }
}

//
var arr = []int{1, 2, 4, 8, 16, 32, 64, 128}

func main() {
    for i, v := range arr {
        fmt.Printf("2**%d = %d\n", i, v)
    }
    for _, v := range arr {
        fmt.Printf(v)
    }
    for i := range arr {
        fmt.Printf(i)
    }
}


if, switch 문

if j:= math.Pow(1,2); j < 100 {
    fmt.Println(j) 
}else{
    // j는 if, else 안에서만 사용
    fmt.Println(j)
}

import "runtime"
switch os := runtime.GOOS; os {
    case "darwin":
        fmt.Println("OS X.")   // break 가 없어도 자동으로 break 된다.
    case os + "_X":
        fmt.Println("Linux.")
    default:
        fmt.Printf("%s.", os)
}

// if--then--else 대용으로 사용하면 된다.
t := time.Now()
switch {   // switch true
    case t.Hour() < 12:
        fmt.Println("Good morning!")
    case t.Hour() < 17:
        fmt.Println("Good afternoon.")
    default:
        fmt.Println("Good evening.")
}



기본 자료형


bool

string

int  int8  int16  int32  int64
uint uint8 uint16 uint32 uint64 uintptr

byte // uint8의 다른 이름(alias)

rune // int32의 다른 이름(alias)
     // 유니코드 코드 포인트 값을 표현합니다. 

float32 float64

complex64 complex128


string 참고 소스


구조체 struct

type Point struct {
    X int
    Y int
}

var (
    p = Pointer{1, 2}  // has type Vertex
    q = &Pointer{1, 2} // has type *Vertex
    r = Pointer{X: 1}  // Y:0 is implicit
    s = Pointer{}      // X:0 and Y:0
)

func main() {
    p := Point{1, 2} // create
    p.X = 4
    q := &p  // pointer 할당
    q.X = 5
    fmt.Println(p.Y)
    fmt.Println(q.X)   // q.X 는 5 가 되고, p.X 도 5가 된다.

    //
    v := new(Pionter)  // new 는 필드를 '0' 으로 초기화 한다.
    v.X = 5
    var w *Pointer = new(Pointer)  // w:= new(Pointer)
    w.X = 10

}

go 는 pointer 가 있지만, pointer 연산은 안된다.


class 문법

class 는 없고, struct 에 함수를 추가할 수 있다.(결국 이름 붙이기 나름이긴 하다. ) 여하튼 이때 pointer type 과 일반적인 type 으로 method receiver 를 설정할 수 있다. 자세한 것은 여기를 참고하자.

// modified while the server is running.
type Server struct {
 running bool
}

// Peers returns all connected peers.
func (srv *Server) Peers() []*Peer {
 var ps []*Peer
 select {
 // Note: We'd love to put this function into a variable but
 // that seems to cause a weird compiler error in some
 // environments.
 case srv.peerOp <- func(peers map[discover.NodeID]*Peer) {
  for _, p := range peers {
   ps = append(ps, p)
  }
 }:
  <-srv.peerOpDone
 case <-srv.quit:
 }
 return ps
}


//
//  기존 type 에 함수를 추가, 기본 type 에는 추가할 수 없지만, 아래처럼 새롭게 자신의 type 을 선언하면 된다.
//  그리고 다른 package 에 있는 type 에 추가할 수는 없다.
//
type MyFloat float64

func (f MyFloat) Abs() float64 {
    if f < 0 {
        return float64(-f)
    }
    return float64(f)
}

func main() {
    f := MyFloat(-math.Sqrt2)
    fmt.Println(f.Abs())
}



strconv

string --> int


i, err := strconv.Atoi("-42")
s := strconv.Itoa(-42)



interface


변수선언할 때 interface{} type 은 Java 의 object처럼 가장 상위 개념의 type 이라 봐도 좋을 듯 하다.

interface type 으로 variable 을 하나 선언하면,
이 variable 로 모든 interface type 을 받을 수 있고, primitive type 도 받을 수 있기 때문이다.


func main() {
 var i interface{} = 3.0
 s := i.(float64)
 fmt.Println(s)

 s, ok := i.(float64)
 fmt.Println(s, ok)

 f, ok := i.(string)
 fmt.Println(f, ok)

 f = i.(string) // panic
 fmt.Println(f)
}

import "strconv"

type Stringer interface {
    ToString() string
}

func main() {
    var a Stringer
    f := MyFloat(103.22)
    v := Vertex{3.0, 4.0}

    a = f  // a MyFloat implements Stringer
    a = &v // a *Vertex implements Stringer
    a = v  // Error: a Vertex, does NOT implement Stringer

    fmt.Println(a.Abs())
}

// MyFloat
type MyFloat float64

func (f MyFloat) ToString() string {
    return strconv.FormatFloat(f, 'f', -1, 64)  // infinite precision '-1' , 64 bit
}

// Vertex
type Vertex struct {
    X, Y float64
}

func (v *Vertex) ToString() string {
 return strconv.Itoa(v.X)
}


type assertions

이 때 이 interface 가 가진 child 에 따라 동작을 하도록 하려면, 아래처럼 (type) 과 switch 를 이용할 수 있다.

type Stringer interface {
    String() string
}
var value interface{} // Value provided by caller.
switch str := value.(type) {
case string: 
    return str
case Stringer:
    return str.String()
}



function pointer

함수를 parameter 로 넘기는 것은 간단하다.

func paramFunc(title string) int{
 fmt.Println(title)
 return 1
}
func testFuncPointer(fn func(string) int) int{
 ret := fn("test")
 return ret
}
func main() {
 testFuncPointer(paramFunc)
}


file i/o

import "io/ioutil"
var body = []byte("Test")
ioutil.WriteFile(filename, body, 0600) // 0600 is permission
body, error := ioutil.ReadFile(filename)



defer

이 녀석은 python 의 with 같다. java 의 fianlly 와도 비슷하다. 근데 약간 이름이 부자연스럽긴 하다.

아래 코드에서 defer 는 function 이 끝나는 시점에 수행된다. 즉, writeFile 을 하고 난 후에 closeFile 이 실행된다.

func main() {
    f := createFile("/tmp/defer.txt")
    defer closeFile(f)
    writeFile(f)
}




thread

go 에서는 goroutine 으로 불린다.  go 뒤에 수행하고 싶은 function 을 넣으면 된다. 그러면 go func 을 한 순간부터 run 이 되는 것이다.

go func(){ fmt.Println("this is a thread")}



select

대략적으로 이야기하면, queue 에서 값을 가져와서 어떤 작업을 하는 녀석(예를 들면, dispatcher) 을 만들 때 사용하면 된다.(좀 더 응용해서 어떤 신호를 받을 때 사용하면 된다.)

select 가 만약 default 를 가지고 있으면, queue 가 empty 일때 default 가 호출된다. 그리고 default 가 없다면, queue 에 item 이 들어올 때 까지 block 된다.(참고)

type Job func()

type worker struct {
    jobChannel chan Job

}


func (w *worker) start() {
    // new thread start
    go func() {
        var job Job
        for {

            select {
            case job = <-w.jobChannel:
                job()

            }
        }
    }()
}



예제

package main

import (
    "fmt"
    "os"
    "bufio"
    "strings"   
    "strconv"
)

func main() {
 fmt.Println("Hello, 世界")
    var caseCount, cPlank int
    
    fmt.Scanf("%d\n", &caseCount)
    
    for i := 0; i<caseCount; i++{
        var hlist []int32
        fmt.Scanf("%d\n", &cPlank)
        
        reader := bufio.NewReader(os.Stdin)
        fmt.Print("Enter text: ")
        text, _ := reader.ReadString('\n')
        text = strings.TrimRight(text, "\r\n")
        
        // convert string to []int
        // "3 2 4" --> [3, 2, 4]
        splitStr := strings.Split(text, " ")
        for _, s := range splitStr{
            pint, err := strconv.ParseInt(s, 10, 64)
            if err != nil{
                fmt.Print("error")
                fmt.Println(err)
            }
            hlist = append(hlist, int32(pint))    
        }
        fmt.Println(hlist)
    }
    
}


See Also

  1. A Tour of Go
  2. Go by Example
  3. avelino/awesome-go: A curated list of awesome Go frameworks, libraries and software
  4. Projects · golang/go Wiki
  5. Learn Go by writing tests – Hello, world : https://github.com/quii/learn-go-with-tests/tree/master/hello-world




댓글 없음:

댓글 쓰기