Grammar
문법 25개 키워드#
var#
변수 선언
func main() {
var x int
println(x)
x = 2
println(x)
var a, b, c int = 1, 2, 3
println(a, b, c)
}
//OUTPUT
0
2
1 2 3
const#
상수 선언
func main() {
const x int = 1
println(x)
const (
a = 2
b = 3
c = 4
)
println(a + b + c)
}
//OUTPUT
1
9
for#
반복문
func main() {
sum := 0
for i := 1; i <= 10; i++ {
sum += i
}
println("sum :", sum)
i, sum2 := 0, 0
for i < 10 {
i++
sum2 += i
}
println("sum2 :", sum2)
}
//OUTPUT
sum : 55
sum2 : 55
range#
컬렉션에서 각 요소의 인덱스와 값을 반환
func main() {
numbers := []int{1, 2, 3}
for index, num := range numbers {
println(index, num)
}
}
//OUTPUT
0 1
1 2
2 3
break#
for
, switch
, select
에서 빠져나올 때 사용
func main() {
i := 0
for i < 10 {
i++
if i == 5 {
break
}
}
println("i :", i)
}
//OUTPUT
i : 5
continue#
for
루프 시작 부분으로 이동
func main() {
i := 0
for i < 5 {
i++
if i == 3 {
continue
}
println("i :", i)
}
}
//OUTPUT
i : 1
i : 2
i : 4
i : 5
switch#
여러 값을 비교하는 조건문 표현
func main() {
num := 5
switch {
case num == 10:
println("num is 10")
case num == 8:
println("num is 8")
case num == 5:
println("num is 5")
default:
println("num is less than 5")
}
}
//OUTPUT
num is 5
case#
조건문을 작성
func main() {
num := 1
switch num{
case 1, 2:
println("num is 1 or 2")
case 3, 4:
println("num is 3 or 4")
default:
println("num is more than 5")
}
}
//OUTPUT
num is 1 or 2
default#
모든 case
에 부합하지 않을 때 실행
func main() {
num := 3
switch {
case num == 10:
println("num is 10")
case num == 8:
println("num is 8")
case num == 5:
println("num is 5")
default:
println("num is less than 5")
}
}
//OUTPUT
num is less than 5
fallthrough#
case
를 만족해도 아래의 case
들을 실행하기 위해 fallthrough 를 사용
go 컴파일러가 자동으로
break
문을 각case
문 블럭 마지막에 추가하므로, 조건문이 해당하는 경우 해당case
에서switch
문이 종료된다.
func main() {
num := 1
switch {
case num < 10:
println("num is less than 10")
fallthrough
case num < 8:
println("num is less than 8")
fallthrough
default:
println("num is less than 5")
}
}
//OUTPUT
num is less than 10
num is less than 8
num is less than 5
if#
조건문
func main() {
a := 1
if a == 0 {
println("a is 0")
}
println("a is", a)
}
//OUTPUT
a is 1
else#
if
조건식이 모두 거짓일 때 실행
func main() {
a := 1
if a == 0 {
println("a is 0")
} else if a == 2 {
println("a is 2")
} else {
println("a is 1")
}
}
//OUTPUT
a is 1
func#
함수 선언
func main() {
sum(5, 10)
}
func sum(a int, b int) {
println("sum :", a+b)
}
return#
값을 반환
func main() {
println(sum(5, 10))
println(multiply(5, 10))
}
func sum(a int, b int) (sum int) {
sum = a + b
return
}
func multiply(a int, b int) int {
return a * b
}
//OUTPUT
15
50
defer#
함수 내에서 제일 마지막에 실행
func main() {
defer println("last")
println("first")
}
//OUTPUT
first
last
package#
코드의 모듈화, 코드의 재사용 가능 * main 패키지 : 실행 프로그램 * 그 외 패키지 : 공유 패키지(라이브러리)
import#
다른 패키지를 사용하기 위해 포함시킬 것을 선언
import "fmt"
func main() {
fmt.Println("fmt package")
}
//OUTPUT
fmt package
type#
새로운 타입 정의
struct#
변수를 묶어서 새로운 자료형 정의 (Custom Data Type)
type hotel struct {
name string
price int
}
func main() {
var h1 = hotel{}
h1.name = "abc"
h1.price = 5000
h2 := hotel{name: "cde", price: 1000}
fmt.Println(h1, h2)
}
//OUTPUT
{abc 5000} {cde 1000}
interface#
메소드들의 집합체
type reserve interface {
twoday() int
}
type hotel struct {
name string
price int
}
type airbnb struct {
name string
price int
coupon int
}
func (h hotel) twoday() int {
return h.price * 2
}
func (a airbnb) twoday() int {
return a.price*2 - a.coupon
}
func main() {
a := hotel{"aaa", 1000}
b := airbnb{"bbb", 1000, 500}
makeReserve(a, b)
}
func makeReserve(r ...reserve) {
for _, v := range r {
fmt.Println(v.twoday())
}
}
//OUTPUT
2000
1500
map#
해시테이블을 구현한 자료구조
func main() {
m := map[string]int{
"one": 1,
"two": 2,
}
m["five"] = 5
for k, v := range m {
println(k, v)
}
}
//OUTPUT
one 1
two 2
five 5
go#
go
키워드로 함수를 호출하면, goroutine 실행
func main() {
go num(1)
go num(2)
go num(3)
time.Sleep(time.Second * 3)
}
func num(n int) {
println(n)
}
//OUTPUT
3
1
2
chan#
채널 선언 * 채널 : 고루틴 사용시 값을 주고 받는 통로
func main() {
ch := make(chan int)
go func() {
ch <- 1
}()
num := <-ch
println(num)
}
//OUTPUT
1
select#
다중 채널사용시 채널 분기문으로 사용
func main() {
c1 := make(chan string)
c2 := make(chan string)
go func() {
time.Sleep(1 * time.Second)
c1 <- "one"
}()
go func() {
time.Sleep(2 * time.Second)
c2 <- "two"
}()
for i := 0; i < 2; i++ {
select {
case msg1 := <-c1:
fmt.Println("received", msg1)
case msg2 := <-c2:
fmt.Println("received", msg2)
}
}
}
goto#
특정 레이블로 이동
func main() {
num := 1
if num == 1 {
goto ONE
} else {
goto OTHER
}
ONE:
println("num is 1")
goto END
OTHER:
println("num is not 1")
END:
//OUTPUT
num is 1
}
Reference
[strconv] Convert uint64 to string#
package main
import (
"fmt"
"strconv"
)
func main() {
// Create our number
var myNumber uint64
myNumber = 18446744073709551615
// Format to a string by passing the number and it's base.
str := strconv.FormatUint(myNumber, 10)
// Print as string
// Will output: 'The number is: 18446744073709551615'
fmt.Println("The number is: " + str)
}
Reference
https://golangcode.com/uint64-to-string/
[strconv] convert uint8 to string#
strconv.Itoa(int(123))
Reference
https://stackoverflow.com/questions/19223277/how-to-convert-uint8-to-string
[os/exec] 커맨드 명령어 실행하기 in go#
package main
import (
"fmt"
"os"
"os/exec"
"strings"
)
func main() {
// 1. Create an *exec.Cmd
// cmd := exec.Command("go", "version")
// // Stdout buffer
// cmdOutput := &bytes.Buffer{}
// // Attach buffer to command
// cmd.Stdout = cmdOutput
// // Execute command
// printCommand(cmd)
// err := cmd.Run() // will wait for command to return
// printError(err)
// // Only output the commands stdout
// printOutput(cmdOutput.Bytes())
// 2. Create an *exec.Cmd
cmd := exec.Command("go", "version")
// Combine stdout and stderr
printCommand(cmd)
output, err := cmd.CombinedOutput()
printError(err)
printOutput(output)
}
func printCommand(cmd *exec.Cmd) {
fmt.Printf("==> Executing: %s\n", strings.Join(cmd.Args, " "))
}
func printError(err error) {
if err != nil {
os.Stderr.WriteString(fmt.Sprintf("==> Error: %s\n", err.Error()))
}
}
func printOutput(outs []byte) {
if len(outs) > 0 {
fmt.Printf("==> Output: %s\n", string(outs))
}
}
Reference
출처: https://www.darrencoxall.com/golang/executing-commands-in-go
[iconv-go] byte to string 변환시 한글깨짐 해결#
간혹 byte를 string 으로 출력시 한글깨짐 현상을 겪을 수 있다.
이때 가장 합리적인 해결 방안.
result, _ := iconv.ConvertString(string(output), "euc-kr", "utf-8")
윈도우 사용자:
윈도우는 gcc 활성화를 위해서 MinGW를 설치해야 한다.(키보드 관련 go 라이브러리도 마찬가지)
인스톨 파일이 작동되지 않는다면 압축파일 받아서 ProgramFiles 에 압축해제해서 떨궈놓고 환경변수(mingw64/bin)만 셋팅하면 된다.
Reference
https://github.com/djimenez/iconv-go
aes256 cbc 암호화 복호화#
PKCS5Padding#
base64:
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"encoding/base64"
"fmt"
)
func AESEncrypt(src string, key []byte, iv string) string {
block, err := aes.NewCipher(key)
if err != nil {
fmt.Println("key error1", err)
}
if src == "" {
fmt.Println("plain content empty")
}
ecb := cipher.NewCBCEncrypter(block, []byte(iv))
content := []byte(src)
content = PKCS5Padding(content, block.BlockSize())
crypted := make([]byte, len(content))
ecb.CryptBlocks(crypted, content)
return base64.StdEncoding.EncodeToString(crypted)
}
func AESDecrypt(cryptedStr string, key []byte, iv string) []byte {
encryptedData, _ := base64.StdEncoding.DecodeString(cryptedStr)
block, err := aes.NewCipher(key)
if err != nil {
fmt.Println("key error1", err)
}
if len(encryptedData) == 0 {
fmt.Println("plain content empty")
}
ecb := cipher.NewCBCDecrypter(block, []byte(iv))
decrypted := make([]byte, len(encryptedData))
ecb.CryptBlocks(decrypted, encryptedData)
return PKCS5Trimming(decrypted)
}
func PKCS5Padding(ciphertext []byte, blockSize int) []byte {
padding := blockSize - len(ciphertext)%blockSize
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
return append(ciphertext, padtext...)
}
func PKCS5Trimming(encrypt []byte) []byte {
padding := encrypt[len(encrypt)-1]
return encrypt[:len(encrypt)-int(padding)]
}
hex:
func Ase256Encode(plaintext string, key string, iv string, blockSize int) string {
bKey := []byte(key)
bIV := []byte(iv)
bPlaintext := PKCS5Padding([]byte(plaintext), blockSize, len(plaintext))
block, err := aes.NewCipher(bKey)
if err != nil {
panic(err)
}
ciphertext := make([]byte, len(bPlaintext))
mode := cipher.NewCBCEncrypter(block, bIV)
mode.CryptBlocks(ciphertext, bPlaintext)
return hex.EncodeToString(ciphertext)
}
func Ase256Decode(cipherText string, encKey string, iv string) (decryptedString string) {
bKey := []byte(encKey)
bIV := []byte(iv)
cipherTextDecoded, err := hex.DecodeString(cipherText)
if err != nil {
panic(err)
}
block, err := aes.NewCipher(bKey)
if err != nil {
panic(err)
}
mode := cipher.NewCBCDecrypter(block, bIV)
mode.CryptBlocks([]byte(cipherTextDecoded), []byte(cipherTextDecoded))
return string(cipherTextDecoded)
}
func PKCS5Padding(ciphertext []byte, blockSize int, after int) []byte {
padding := (blockSize - len(ciphertext)%blockSize)
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
return append(ciphertext, padtext...)
}
[time] YYYY-MM-DD date format 사용하기#
Datetime Format Layout#
const (
Layout = "01/02 03:04:05PM '06 -0700" // The reference time, in numerical order.
ANSIC = "Mon Jan _2 15:04:05 2006"
UnixDate = "Mon Jan _2 15:04:05 MST 2006"
RubyDate = "Mon Jan 02 15:04:05 -0700 2006"
RFC822 = "02 Jan 06 15:04 MST"
RFC822Z = "02 Jan 06 15:04 -0700" // RFC822 with numeric zone
RFC850 = "Monday, 02-Jan-06 15:04:05 MST"
RFC1123 = "Mon, 02 Jan 2006 15:04:05 MST"
RFC1123Z = "Mon, 02 Jan 2006 15:04:05 -0700" // RFC1123 with numeric zone
RFC3339 = "2006-01-02T15:04:05Z07:00"
RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00"
Kitchen = "3:04PM"
// Handy time stamps.
Stamp = "Jan _2 15:04:05"
StampMilli = "Jan _2 15:04:05.000"
StampMicro = "Jan _2 15:04:05.000000"
StampNano = "Jan _2 15:04:05.000000000"
)
YYYY-MM-DD#
package main
import (
"fmt"
"time"
)
const (
YYYYMMDD = "2006-01-02"
)
func main() {
now := time.Now().UTC()
fmt.Println(now.Format(YYYYMMDD))
}
//output: 2022-03-14
DD/MM/YYYY#
package main
import (
"fmt"
"time"
)
const (
DDMMYYYY = "02/01/2006"
)
func main() {
now := time.Now().UTC()
fmt.Println(now.Format(DDMMYYYY))
}
//output: 14/03/2022
YYYY-MM-DD hhss#
package main
import (
"fmt"
"time"
)
const (
DDMMYYYYhhmmss = "2006-01-02 15:04:05"
)
func main() {
now := time.Now().UTC()
fmt.Println(now.Format(DDMMYYYYhhmmss))
}
//output: 2022-03-14 05:41:33
[time] 문자열 파싱#
input := "2020-10-24"
layout := "2006-01-02"
t, _ := time.Parse(layout, input)
fmt.Println(t) // 2020-10-24 00:00:00 +0000 UTC
[ioutil.TempFile] 임시파일 생성하는 방법#
IO / ioutil 패키지는 두 가지 기능을 포함하고 임시 디렉토리 TempDir 및 임시 파일 TempFile 을 만들 수 있습니다.
유닉스 머신에서 기본적으로 TempDir 함수는/tmp/임시 디렉토리로반환됩니다.접두사가있는 디렉토리를 작성하기 위해 추가 매개 변수를 전달할 수 있습니다.
TempFile 함수는 고유하고 임의의 숫자를 만듭니다.pattern매개 변수를 사용하여 파일의 접두사와 접미사를 제어 할 수 있습니다. 예로 *.tmp 를 전달하면 임시 파일이 생성됩니다.프로그램에서 임시 파일을 삭제하지 않고 나중에 임시 파일을 정리하는 일괄 삭제 작업을 원하는 경우에 유용합니다.
파일을 만든 후에는 파일 형식 그대로 파일에 무엇이든 쓸 수 있습니다
os.File.os.File은 io.ReadWriter 인터페이스를 구현하므로 Write메소드를 사용하여 파일에 쓸 수 있습니다.
package main
import (
"fmt"
"io/ioutil"
"os"
)
func main() {
// Create a Temp File: This will create a filename like /tmp/pre-23423234
// If we use a pattern like "pre-*.ext", you can get a file like: /tmp/pre-23423234.ext
tmpFile, err := ioutil.TempFile(os.TempDir(), "pre-")
if err != nil {
fmt.Println("Cannot create temporary file", err)
}
// cleaning up by removing the file
defer os.Remove(tmpFile.Name())
fmt.Println("Created a Temp File: " + tmpFile.Name())
// Write to the file
text := []byte("Writing some text into the temp file.")
if _, err = tmpFile.Write(text); err != nil {
fmt.Println("Failed to write to temporary file", err)
}
// Close the file
if err := tmpFile.Close(); err != nil {
fmt.Println(err)
}
}
io/ioutil -> io 옮겨간 메서드#
- ioutil.ReadAll => io.ReadAll
- ioutil.ReadDir => os.ReadDir
- ioutil.ReadFile => os.ReadFile
- ioutil.TempDir => os.MkdirTemp
- ioutil.TempFile => os.CreateTemp
- ioutil.WriteFile => os.WriteFile
Reference
https://runebook.dev/ko/docs/go/io/ioutil/index
bool 에서 int8 로 변환하기#
package main
import "fmt"
func B2i(b bool) int8 {
if b {
return 1
}
return 0
}
func main() {
fmt.Println(B2i(true)) // 1
fmt.Println(B2i(false)) // 0
}
Reference
https://stackoverflow.com/questions/38627078/how-to-convert-bool-to-int8-in-golang