튼튼발자 개발 성장기🏋️

기본 문법 본문

프로그래밍/GoLang

기본 문법

시뻘건 튼튼발자 2024. 12. 28. 14:55
반응형
더보기

GO 언어 관련해서 기본적인 문법 내용은 github에 정리해두었다.

 

변수, 상수 그리고 열겨형

변수를 선언할 때 변수 명에는 공백을 포함하지 않은 문자, 숫자, 언더스코어(_)를 사용할 수 있고 숫자는 첫 글자에 사용할 수 없다. golang에서는 대소문자를 구분한다는 점에 유의해야한다. 참고로 golang은 camel case를 사용하는 것을 권장한다.

변수를 선언하는 방법은 크게 4가지가 있다.

  1. var 키워드로 선언하고 var 다음에 변수 이름과 타입을 표기한다.
  2. 같은 타입인 변수를 선언할 경우 콤마(,)로 구분하여 선언할 수 있다.
  3. 서로 다른 타입의 변수를 선언할 경우 소괄호로 묶어서 한 번에 선언할 수 있다.
  4. 변수 선언과 동시에 값을 정의할 경우 타입을 생략할 수 있고, := 연산자를 사용할 수도 있다.
var a int
var b string

var name, age, address string

var (
	name string
	age int
	weight dloat
)

var c = true
name := "small-goliath"

 

상수란 처음 선언한 이후 변하지 않는 변수를 의미한다. 상수의 경우에는 const 키워드를 사용하여 선언할 수 있다. 상수는 bool, 숫자, 문자열 타입으로만 선언할 수 있다.

상수는 컴파일할 때 값이 정해진다. 특정 계산식의 결과를 상수로 지정할 수 있는데, 이런 계산식은 컴파일할 때 연산할 수 있어야한다.

const limit - 64
const max unit64 = 1024

const max = 1024 * 1024
const  = getNumber()	// 유효하지 않음

const (
	RED = 0
	ORANGE = 1
	YELLOW = 2
)

 

golang은 특이하게도 다른 언어에서 기본적으로 사용하는 개면을 사용하지 않는 경우가 많다. 열거형이 그 중 하나인데, 상수와 열거형에 차이를 두지 않는다.

상수를 선언할 때 iota 예약어를 사용하면 편리하다. 상수를 그룹으로 묶어서 선언할 때, const 그룹에서 iota의 값은 0이고 이후로는 1씩 증가하는 개념이다.

const (
	RED = iota	// 0
	ORANGE		// 1
	YELLOW		// 2
)

 

흐름제어

흔히 다른 언어처럼 if문, switch문, for문, select문으로 나눌 수 있는데 select문의 경우에는 병행 처리 코드를 작성할 때 채널을 제어하기 위해 사용되므로 기본 문법에서 다루기엔 양이 상당해서 다음에 언급 하도록 하겠다.

조건문

if문의 조건식에는 bool type만 사용이 가능하기 때문에 0과 1은 조건식에 사용할 수 없다. 조건문을 제어하는 break, continue, goti, return이 등장할 때는 else를 생략하면 간결해질 수 있다.

if문에는 초기화 구문도 작성할 수 있는데, 초기화 구문과 조건식은 세미콜론(;)으로 구분하며 초기화 구문에서 선언된 변수는 if문 내에서만 사용할 수 있다.

is := true
not := false

if is {
	// ...
} else if not {
	// ...
} else {
	// ...
}

if v := compute(); v < 0 {
	fmt.Println(v, "는 음수입니다.")
}

 

switch문도 마찬가지로 중괄호가 필수이다. 값을 둘 이상 사용할 때는 콤마로 구분해주어야한다.

일치하는 case문을 만나면 break가 없어도 바로 switch 문을 빠져나오는 점에 유의해야한다. 이 때, 다음 case로 넘어가려면 fallthrough를 사용해야한다.

만약 switch문에 변수를 사용하지 않으면 첫 번째로 true인 case 조건을 실행한다.

switch i {
case -1, -2:
	fmt.Println(i, "는 음수입니다.")
case 1, 2:
	fmt.Println(i, "는 양수입니다.")
default:
	fmt.Println(i, "는 0입니다.")
}

switch i {
case 1:
	fmt.Println("i는 1보다 작거나 같습니다.")
	fallthrough
case 2:
	fmt.Println("i는 2보다 작거나 같습니다.")
	fallthrough
case 3:
	fmt.Println("i는 3보다 작거나 같습니다.")
}

i := -2
switch {
case i < 0:
	fmt.Println(i, "는 음수입니다.") // 실행
case i == 0:
	fmt.Println(i, "는 0입니다.")
case i > 0:
	fmt.Println(i, "는 양수입니다.")
}

 

반복문

golang에는 while문이 없다. 보통 상황에 따라서 for문과 while문을 사용하는데, golang은 모든 반복문을 for문으로 사용한다.

초기화 구문, 조건식, 후속 작업은 세미콜론으로 구분하게 되는데, 모든 구문은 생략할 수 있다.

for문에 레이블을 사용하여 식별자를 붙일 수 있으며 break를 더 유용하게 사용할 수 있다.

for i := 0; i < COUNT; i++ {
	// ...
}

for {
	// ...
}


i = 11
sum = 0
LOOP:
for {
    i -= 1

    if i%2 == 1 {
        sum += i
        break LOOP
    }
}

 

함수

golang은 call by value가 기본이다. 이에 유의하여 함수를 작성해야하며 call by reference를 사용해야할 때 포인터와 주소 값을 잘 활용해야한다. (C언어와 동일)

함수의 접근제어, 매개변수, 익명함수, 클로저 등에 관한 내용을 알아보자.

기본적으로 func 키워드로 선언하며 함수명과 매개변수, 반환 타입 또는 반환 값이 위치한다.

func 함수명(매개변수) (반환타입 또는 반환 값) {
	// ...
}

 

매개변수가 여러 개일 경우 콤마로 구분하여 작성하며 같은 타입인 매개변수가 여러 개이면 매개변수 이름을 콤마로 구분한다. golang의 경우에도 가변인자를 사용할 수 있는데 닷(.) 세개를 사용하여 나타낸다.

func myFunc(b bool, s string, i, j, k int, num ...int) {
	// ...
}

 

golang은 python과 비슷하게 하나 이상의 값을 리턴할 수 있다. 리턴 값이 두 개 이상일 경우에만 괄호를 사용하여 리턴한다. 만약 필요 없는 리턴값이라면 언더 스코어를 사용하여 ignore할 수 있다.

func myFunc() int {
	return 10
}

func myFunc2() (int, string) {
	return (10, "십")
}

num, name := myFunc2()
num, _ := myFunc2()	// 두 번쨰 리턴값 무시

 

defer 키워드는 함수가 종료되기 전까지 특정 구문의 실행을 지연시켰다가 함수가 종료되기 직전에 수행한다. 주로 리소스를 해제시키거나 클렌징 작업이 필요할 때 사용한다.

func main() {
	WhatIsDefer()
}

func Defer() {
	fmt.Println("Defer END!")
}

func WhatIsDefer() {
	fmt.Println("WhatIsDefer() START!")
	defer Defer()
	fmt.Println("WhatIsDefer() END!")
}


/*
WhatIsDefer() START!
WhatIsDefer() END!
Defer END!
*/

 

때로는 함수 이름을 지정하지 않고 사용하는 익명함수를 사용할 때가 있다. golang에서 함수는 일급 객체이므로 변수의 값으로 사용할 수 있다. 다음과 같이 함수를 변수에 할당하여 변수처럼 사용할 수 있다.

아래 예제 코드를 보면 마지막에 (1, 1)로 함수를 호출한 것을 볼 수 있는데 이런 익명 함수를 클로저라 한다.

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

fmt.Println(func(x, y int) int {
    return x + y
}(1, 1))


// closure
addZip := ClosureName(".zip")
addTar := ClosureName(".tar")
fmt.Println(addZip("Clo"))
fmt.Println(addTar("sure"))

 

함수를 매개변수로 전달할 수도 있다.

func main() {
	FuncArgs(3, Display3)
}

func FuncArgs(num int, f func(int, string)) {
	f(num, "나를 출력해줘")
}

func Display3(num int, str string) {
	fmt.Printf("num: %d, str: %s\n", num, str)
}

 

init() 함수는 패키지가 로드될 때 가장 먼저 호출되는 함수로, 패키지의 초기화 로직이 필요할 때 선택적으로 사용할 수 있다.

package main

import (
	"fmt"
)

var v rune

func init() {
	v = '1'
	fmt.Println("init 함수는 패키지가 로드될 때 호출된다.")
}

func main() {
	// ...

}

 

반응형