Go) Golang 기초
1. Golang의 특징
- Golang은 구글이 개발한 정적 타입, 컴파일 언어로, 간결한 문법과 빠른 컴파일 속도, 내장된 동시성 지원이 특징인 언어다.
- 특히 서버 사이드, 분산 시스템, CLI 도구 개발에서 많이 쓰이며, 하나의 바이너리로 배포가 가능해 운영 측면에서도 장점이 크다.
- 클래스가 없다. 구조체와 포인터를 활용해 객체지향을 구현할 수 있다.
2. Golang을 이용하게 된 이유
- 직무 상, 가장 많이 만지는 언어는 역시 “Python”이다. 하지만 “Python”은 GIL(Global Interpreter Lock)이라는 제약이 존재한다. 즉 CPU-bound 작업에서 멀티 코어(1코어 이상)을 활용하기 어렵다.(stack overflow)
- 이를 해결하고자 일반적으로 multiprocessing을 이용하지만 이는 메모리 사용량이 배로 높아질 가능성이 크다. 멀티 코어 기반 고성능 컴파일 언어를 찾던 와중, Golang을 알게 되었다.
- 처음엔 C++을 공부 하려 다가, 고성능+단순한 문법에 빠져 실제 회사에서도 이용해보기도 하였다. 또한 실제 개발진들이 C++을 욕(?)하며 해당 언어를 개발하였다는 점도 흥미롭게 다가왔다.
3. 기본 문법
1) 기본 데이터 타입 종류
| 카테고리 | 타입 | 크기 | Zero Value | 비고 |
|---|---|---|---|---|
| 불리언 | bool |
1바이트 | false |
|
| 정수 (부호) | int8 |
1바이트 | 0 | -128 ~ 127 |
int16 |
2바이트 | 0 | ||
int32 (rune) |
4바이트 | 0 | ||
int64 |
8바이트 | 0 | ||
int |
4/8바이트 | 0 | 플랫폼 의존 (추천) | |
| 정수 (부호없음) | uint8 (byte) |
1바이트 | 0 | |
uint16 |
2바이트 | 0 | ||
uint32 |
4바이트 | 0 | ||
uint64 |
8바이트 | 0 | ||
uint |
4/8바이트 | 0 | ||
| 실수 | float32 |
4바이트 | 0.0 | |
float64 |
8바이트 | 0.0 | 실무 표준 | |
| 복소수 | complex64 |
8바이트 | 0+0i | |
complex128 |
16바이트 | 0+0i | ||
| 문자열 | string |
가변 | "" |
불변 UTF-8 |
| 참조 타입 | map[K]V |
- | nil |
make() 필수 |
[]T (slice) |
- | nil |
make() 필수 |
|
*T (포인터) |
- | nil |
new() 또는 & |
2) 변수 선언 방법
- var 선언 (타입 명시)
var name string // 변수 선언 + Zero Value 할당
name = "neo" // 값 재할당
var age int = 30 // 변수 선언 + 값 할당
- 단축 선언 (타입 추론)
name := "neo" // string 자동 추론
age := 30 // int 자동 추론
3) 함수 정의 방법
- 미반환 함수
func log(msg string) {
log.Print("[log] " + msg)
}
// 사용 예시
log("Hello World") // "[log] Hello World"
- 반환 함수
func add(a int, b int) int {
var c int
c = a + b
return c
}
// 사용 예시
c := add(1, 2) // c는 3
- 포인터 활용 함수
func add(c *int, a int, b int) {
*c = a + b
}
// 사용 예시
var c int
add(&c, 1, 2) // c는 3
4. 기본 사용 예시
1) 예시 파일 구조
📁 프로젝트 구조 예시: 하나의 모듈은 하나 이상의 패키지로 구성됨
myapp/
├── go.mod # 모듈 정의
├── main.go # package main
└── utils/
├── helper.go # package utils
└── calc.go # package utils (같은 패키지)
2) go.mod
📁 go.mod 파일 역할: 모듈 식별자, 의존성 관리 파일(python 기준 : myapp.toml + requirements.txt)
module myapp // 프로젝트 전체 이름
// module github.com/neatynut/myapp // ✅ GitHub에 올릴 때(공유 시)
go 1.22 // 최소 Go 버전 요구사항
require ( // 직접 사용하는 외부 패키지들
github.com/gin-gonic/gin v1.9.1 // 웹 프레임워크
github.com/sirupsen/logrus v1.9.3 // 로깅
)
require github.com/spf13/viper v1.18.2 // indirect (간접 의존성, 자동 추가)
3) main.go
📁 main.go 파일 역할: 프로그램 진입 점(main() 실행)
package main
import (
"fmt" // 기본 go 패키지
)
func main() {
fmt.Println("Hello, neo")
}
package: python에서*.py또는class단위로 import 가능하다. 이와 비슷한 단위로 이해하였다.import: 외부에서 package를 이용할 때 사용(python의import와 동일)
4) 모듈 구성 예시
- 주의 사항
- 같은 패키지는 같은 폴더에 위치해야 함
- 패키지 간 순환 import(import cycle) 불가
📁 utils/helper.go 예시
package utils
import "fmt"
// 공개 함수: 문자열 인사말 생성
func Greet(name string) string {
return "Hello, " + name + "!"
}
// 내부 전용 함수 (같은 패키지만 사용)
func log(msg string) {
fmt.Println("[LOG]", msg)
}
exportedvsunexported: 대/소문자 시작 여부Greet함수는 package main/utils 에서 사용 가능하나log함수는 package utils 내부에서만 사용 가능
📁 utils/calc.go 예시
package utils
// 공개 구조체 + 메서드
type Calculator struct {
Name string
}
// 값 리시버: 읽기 전용
func (c Calculator) Add(a, b int) int {
return a + b
}
// 포인터 리시버: 상태 변경
func (c *Calculator) Multiply(result *int, a, b int) {
*result = a * b
log("Multiplied: " + c.Name) // 같은 패키지 내부 함수 호출
}
값 리시버vs포인트 리시버
| 항목 | 값 리시버(u User) |
포인터 리시버(u *User) |
|---|---|---|
| 전달 방식 | 복사본 전달 | 주소 전달(8바이트) |
| 원본 변경 | ❌ 불가능 | ✅ 가능 |
| 메모리 복사 | 구조체 전체 복사 | 주소만 복사 |
| 용도 | 읽기전용(getter) | 쓰기/변경(setter) |
- 값 리시버, 포인터 리시버가 상황에 따라 잘 사용해야 하는 이유
- 성능 최적화 : 구조체의 용량이 클때, 메모리 주소 만을 넘기는 포인터 리시버가 유리할 수 있음.
- 안정성 : 원본 변경에 제약을 둬야 할때, 값 리시버가 유리.
📁 main.go의 utils 사용 예시
package main
import (
"fmt"
"myapp/utils" // 내부 패키지 포함
)
func main() {
// helper.go 함수 사용
fmt.Println(utils.Greet("neo")) // Hello, neo!
// calc.go 구조체 + 메서드 사용
calc := utils.Calculator{Name: "basic"}
sum := calc.Add(2, 3)
fmt.Println("2+3 =", sum) // 2+3 = 5
var product int
calc.Multiply(&product, 4, 5)
fmt.Println("4*5 =", product) // 4*5 = 20
}
- 이때 main 패키지에서 utils 패키지를 import 했기에, utils 패키지가 main 패키지를 import 하여 사용하는 것이 불가능
댓글남기기