Go Lang

7 minute read

지금 있는 그대로도 좋다.


주석 및 MainPermalink


package main

import "fmt"

// 이것이 주석이다. 
// 각 Line의 마지막에 ; 를 붙일 필요가 없다. 
func main(){
  fmt.Println("Helo World")	
}    

문자열 및 논리 연산자 / 연산자Permalink


package main

import "fmt"

func main(){
    fmt.Println(len("Hello World"))
    fmt.Println("Hello World"[1])
    fmt.Println("Hello " + "World")
}      


package main

import "fmt"

func main(){
   fmt.Println(true && true)
   fmt.Println(true && false)
   fmt.Println(true || true)
   fmt.Println(true || false)
   fmt.Println(!true)
}

package main

import "fmt"

func main(){
   fmt.Println("1 + 1 =" , 1 + 1 )

   fmt.Println("1 + 1 =", 1.0 + 1.)
}

package main
 
import "fmt"
 
func main() {
    // 문자열에 대해서 아래와 같이 `를 이용하 MultiLine을 이용할 수 있다. 
    fmt.Println(`
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
        `  )
}
       

변수 선언 방식 / 할당 방식 / ==Permalink


package main

import "fmt"

// 사용하지 않는 변수가 선언되 었을 경우 go run 시점에 go가 실행되지 않는다. 

func main(){
  // 변수에 대한 타입 선업은 var {변수명} {타입} 으로 정의된다. 
  var x string
      x = "Hello World"
  fmt.Println(x)
}   

package main

import "fmt"

func main(){
	var x string
        x = "first"
        fmt.Println(x)
        x = "second"
	fmt.Println(x)
}

package main

import "fmt"

func main(){
	var x string = "first"
  var y string = "first"
  
  // 자바와 달리 값에 대한 비교가 == 로 가능하다. 
	fmt.Println(x == y ) // output : true
}

package main

import "fmt"

func main(){

  // Type Inference : 타입 추론 방식으로 문자열에 대한 타입을 변수에 지정하지 않고도 들어온 변수의 타입에 따라 자동으로 지정한다. 
  // 이미 변수에 대한 타입이 지정된 경우에는 Type Inference를 사용할 수 없다. 
  x := "Hello World"

	x = "Hello"	
	
	fmt.Println(x)
}

package main

import "fmt"

//var x string = "Hello World"
func main(){
  // 변수에 대해서 다중으로 선언하여 아래와 같이 사용이 가능하다. 
  // var {변수명} - 타입 추론이 일어난다. 
  var (
    a = 5
    b = 10
    c = "Helo World"
  )
  
  fmt.Println(a, b, c)
}

입력 ( Scanf )Permalink


package main

import "fmt"

func main(){
  fmt.Print("Enter a number:")
  
  var input = 0
  
  // Console 상의 들어오는 입력을 전달 받는 방식 
  // 변수의 주소 값 &input을 던져야 한다. 
  fmt.Scanf("%d", &input)
  
  output := input * 2
  fmt.Println(output)
}

흐름제어Permalink


package main

import "fmt"
  
func main() {
  i := 1
  // for 문을 이용하는 방식은 () 이 필요하지 않고, {}에 코드가 들어간다. 
  for i <= 10 {
    fmt.Println(i)
    i = i + 1
  }

  for i :=  1; i <= 10; i++ {
    fmt.Println(i)
  }

  for i := 1; i <= 10; i ++ {
    if i % 2 == 0 {
      fmt.Println("짝수")		
    }else{
      fmt.Println("홀수")
    }
  }
  
  i = 0 	
 
  // break;라는 개념이 존재하지 않으며, 정확하게 호출된 값에 대해서만 실행되며, 자바와 같이 break;가 없을 때 다음 case 문이 실행되게 할 수 없다.
  switch i {
    case 0 : 
    case 1 : fmt.Println("일")
  }
}

배열/슬라이스/맵Permalink


package main

import "fmt"

func main(){
  // x 변수에 float64의 5개의 배열을 생성할 때, 아래의 코드와 같다. 
  var x [5]float64
  x[4] = 100
  fmt.Println(x)

  var total float64 = 0

  // x 변수의 길이 값을 가져 올 수 있다. 
  for i := 0; i < len(x) ; i ++ {
    total += x[i]
  }

  fmt.Println(total/float64(len(x)))

  // 초기화 시점에 배열에 값을 할당하는 방식 
  x = [5]float64{ 91,12,12,31}

  fmt.Println(x)
    var total1 float64 = 0
    // x 변수의 배열에서 첫번째 값을 받지 않을 때, _ 를 사용하면 사용하지 않음을 의미 한다. 
    // 기본적으로 함수/변수에 대해서 선언되면 Go Lang은 사용해야 한다. 
    for _, value := range x {
    total1 += value
  }

  fmt.Println(total1/float64(len(x)))
}

package main

import "fmt"

func main() {
  
  // arr 변수에 float 배열로 5개의 공간을 구성하는 배열을 반환한다. make : 특정 타입의 메모리를 변수에 할당하는 역할 
  // new와는 달리 해당 타입이 포인터 값이 아닌 값 그 자체를 반환한다. 
	arr := make([]float64, 5 )
	
	fmt.Println(arr)

  // 배열의 갯수를 지정하지 않고 변수를 초기화 시점에 생성하는 방식 
	arrList1 := []int{ 12,123,123}

  arrList2 := make([]int, 1, 10 )

  // arrList1 에 대해서 1부터 2사이의 값을 가져오는 데 기존의 배열에 영향을 미치지 않는다 ( 프로토 타입 )
	arrList4 := arrList1[1:2]

  // int 배열을 4개를 할당하는 것을 의미한다. 
	arrList3 := make([]int, 4 )

  // 기존의 배열 객체에서 배열을 가져와서 신규 배열 객체에 추가하는 방식으로 기존의 배열에는 해당 값이 추가되지 않는다. 
	arrList5 := append(arrList1, 23, 234, 234)

	fmt.Println(arr)
 	fmt.Println(arrList1)
	fmt.Println(arrList2)
	fmt.Println(arrList3)
	fmt.Println(arrList4)
	fmt.Println(arrList5)
  fmt.Println(arrList1)
  
  // 추가 예제 
  // Slice 
  // make(type, length[, capacity])
  s1 := make([]int, 10)
  s2 := make([]int, 10, 100) 

  // Map
  // make(type)
  m := make(map[string]string)

  // Chan
  // make(chan type[, capacity])
  // Unbuffered
  c1 := make(chan int)
  // Buffered
  c2 := make(chan int, 10)
}

package main

import "fmt"

func main(){
  // map 내부에 string이 키인 map을 받을 수 있는 변수를 생성 및 할당
  elements := make(map[string]map[string]string)
  
	elements["H"] = map[string]string{ "OK": "Hydrogen", "haha" : "sdjasf"}

	name := elements["H"]

	fmt.Println(name["OK"], name["haha"])
}

함수Permalink


package main

import "fmt"

func main() {
  // float 배열을 선언
  xs := []float64{91, 22, 34, 23, 34}

  fmt.Println(average(xs))

  // 함수에 대해서 변수를 숫자,숫자 값에 대해서 각각 할당할 수 있음 
  x, y := f()

  fmt.Println(x, y)

  result := add(10, 1, 2, 12, 3, 4)

  fmt.Println(result)
}

func average(xs []float64) float64 {
  total := 0.0
  for _, v := range xs {
    total += v
  }
  return total / float64(len(xs))
}

func f() (int, int) {
  return 10, 20
}

// int에 대한 파라미터를 다중으로 배열과 같이 전달 받아서 이에 대해서 Loop를 돌려 Total를 계산하는 방식 
// range는 다양한 데이터 구조의 요소들을 순회합니다. map에서 range는 key/value 값을 순회합니다. 
func add(args ...int) int {
  total := 0
  // range 
  for _, v := range args {
    total += v
  }
  return total
}

함수의 ClosurePermalink


package main

import "fmt"

func main() {
  add := func(x, y int) int {
    return x + y
  }
  fmt.Println(add(1, 1))

  // 내부 함수가 외부함부의 변수를 참조할 때 해당 변수는 메모리에 할당되며, 함수가 종료되더라고 메모리 상에 상주한다 - Closure
  x := 0

  increment := func() int {
    x++
    return x
  }

  fmt.Println(increment())
  fmt.Println(increment())
  fmt.Println(factorial(3))
}

// Closure를 구현할 수 있는 내부 예제
func factorial(x uint) uint {
  if x == 1 {
    return 1
  }
  return x * factorial(x-1)
}

함수 지연 / Fanic / 복구Permalink


package main

import "fmt"

func main() {
  // defer로 선언된 second 함수는 main 함수가 완료되고 난 이후에 최종적으로 실행된다. 
  defer second()
  first()
}

func first() {
  fmt.Println("1st")
}

func second() {
  fmt.Println("2st")
}            

package main

import "fmt"

func main() {
  // panic은 현재 함수를 즉시 멈추고, 현재 함수에 defer 함수들을 모두 실행한 후 즉시 리턴한다. 
  // 이러한 panic 모드 실행 방식은 상위 함수에도 똑같이 적용되고, 계속 콜 스택을 타고 올라가며 적용된다.
  // 그리고 마지막에는 프로그램이 에러를 내고 종료하게 된다. 
	defer func() {
		str := recover()
		fmt.Println(str)
	}()

	panic("PANIC")
}

함수 포인터Permalink


package main

import "fmt"

func main() {
  x := 5
  zero(&x)
  fmt.Println(x)
}

func zero(xPtr *int) {
  *xPtr = 0
} 

package main

import "fmt"

func one(xPtr *int) {
	*xPtr = 1
}

func main() {
	xPtr := new(int)
	one(xPtr)
	fmt.Println(*xPtr)
}

구조체Permalink


package main

import "fmt"

func main() {

  // 구조체 선언 
  type Circle struct {
    x float64
    y float64
    r float64
  }

  // 구조체를 활용하는 방식 
  c := Circle{x: 0, y: 100, r: 20}

  fmt.Println(c.x, c.y, c.r)

  fmt.Println(c)

  fmt.Println(circleArea(c))

  fmt.Println(c.area())
}

// 함수 구조체에 대해서 메소드 포인터를 이용해서 c.area()에서 구조체의 변수를 사용한다. 
func (c *Circle) area() float64 {
  return c.r * c.r
}

func circleArea(c Circle) float64 {
  return c.r * c.r
}                             
  

GoRoutinePermalink


package main

import "fmt"

func main() {
  // 메인 스레에서 가벼운 스레드를 생성하여 비동기로 프로세스를 실행할 수 있다.
  go f(0)
  go f(10) 

  var input string
  fmt.Scanf("%d", &input)
}

func f(n int) {
  for i := 0; i < 10; i++ {
    fmt.Println(n, ":", i)
  }
}
       

Channel 을 이용한 GoRoutine의 활용Permalink


package main

import (
  "fmt"
  "time"
)

func pinger(c chan string) {
  for i := 0; ; i++ {
    // 채널의 값을 넣는다.
    c <- "ping"
    time.Sleep(time.Second * 5)
  }
}

func printer(c chan string) {
  for {
    // 채널에 가져와서 출력한다. 
    msg := <-c
    fmt.Println(msg)
    time.Sleep(time.Second * 1)
  }
}

func ponger(c chan string) {
  for i := 0; ; i++ {
    // 채널의 값을 넣는다. 
    c <- "pong"
    time.Sleep(time.Second * 2)
  }
}

func main() {
  // make에 의해 채널 을 할당하여 c에 넣는다. 
  var c chan string = make(chan string)

  // 채널에 의해서 값을 채널에 할당하고, 대기 중에 그 값을 채널에서 가져와서 출력한다. 
  // go routine에 의해서 각각의 스레드에서 channel을 공유하여 값을 출련하다. 
  go pinger(c)
  go ponger(c)
  go printer(c)

  var input string
  fmt.Scanln(&input)
}

package main

import (
	"fmt"
	"time"
)

/*
이 프로그램은 "from 1"을 2초마다 출력하고 "from 2"를 3초마다 출력한다. 
select는 준비된 첫 번째 채널을 골라 해당 채널로부터 메시지를 받는다(또는 해당 채널로 메시지를 보낸다). 
하나 이상의 채널이 준비되면 어느 채널로부터 메시지를 받을지 무작위로 선택한다. 
준비된 채널이 없으면 사용 가능해질 때까지 문장 실행이 차단된다.
*/
func main() {
	c1 := make(chan string)
	c2 := make(chan string)

	go func() {
		for {
			c1 <- "from 1"
			time.Sleep(time.Second * 2)
		}
	}()
	go func() {
		for {
			c2 <- "from 2"
			time.Sleep(time.Second * 3)
		}
	}()
	go func() {
		for {
      // Go에는 switch와 비슷하게 동작하지만 채널에 대해서만 동작하는 select라는 특별한 구문이 있다.
			select {
			case msg1 := <-c1:
				fmt.Println(msg1)
			case msg2 := <-c2:
				fmt.Println(msg2)
			}
		}
	}()

	var input string
	fmt.Scanln(&input)
}