Go Lang
지금 있는 그대로도 좋다.
주석 및 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)
}