본문 바로가기

TroubleShooting/Etc

하룻밤에 읽는 Go 언어 이야기

728x90

* 개발 언어별 지원

기능 Go C++ Java
Class X O O
Inheritance X O O
Overloading X O O
GC(Garbage Collector) O X O
Pointer O O X
Pointer 연산 X O X
Import/Package O O(include, namespace) O
Interface O O(template) O
nil O O(NULL, 0) O(null)
Implicit type conversion X O O

* 변수 선언

var a int
var b[10]int
var c, d *int

// var 를 사용하여 그룹으로 묶기
var(
    a int
    f float64
    s string
)

// 선언 시 값을 할당하는 경우 type 생략 가능
var i = 4

// 함수 내에서만 사용되면 ':=' 로 var, type 생략 가능
i := 1

- var a int : 변수 a 는 정수형이다. (Variable a is interger.)

 

* if 문, while 문

if i == 0 {			// () 를 생략가능.
	f()
}

if i == 0			// 컴파일 에러. ';' 이 자동으로 삽입되어 if i == 0 ; 이 된다.
{
	f()
}

for condition {		// while 이라는 키워드가 없다.
	...
}

 * 접근 제한자 - public, private

함수의 첫글자가 대문자로 시작하면 외부 모듈에서 접근 가능한 public, 소문자로 시작하는 경우 외부 모듈에서 접근할 수 없다.

 

* 변수 선언 초기화 값

numeric : 0

boolean : false

string : ""

pointer, map, slice, channel : nil

struct : zeroed struct

 

* 인터페이스

type Drawer interface {
	Draw()
}

type Circle struct {
	r int
}

func (c Circle) Draw() {
	fmt.Println("Circle is Draw : ", c.r)
}

type Rectangle struct {
	w, h int
}

func (r Rectangle) Draw() {
	fmt.Println("Rectangle is w=", r.w, " h=", r.h);
}

func DrawForm(d Drawer) {
	d.Draw()
}

func main() {
	var myC Circle = Circle{5}
	var myR Rectangle = Rectangle{3,4}
 
 	DrawForm(myC)
	DrawForm(myR)
}

* switch 문

switch i {
	case 0, 1 :			// i 가 0 또는 1 인 경우 수행한다.
	doSomeThing()
}

switch {			// switch 만 있는 경우 true 를 기본값으로 가진다
	case i < 0:
		f1()
	case i == 0:
		f2()
	case i < 0:
		f3()
}

* 함수

func add(a, b int) int {
	return a+b
}

func f(i int, j int, k int, s string, t string)
// 동일 함수 인자 묶기
func f(i,j,k int, s,t string)

// 두개 이상의 값을 반환
func add(a, b int) (int, bool) {
	return a+b, true
}

* 배열

var ar [3]int			// 배열 선언
len(ar)					// 사이즈 구하기

[3]int{1,2,3}			// 3개 정수를 갖는 배열
[10]int{1,2,3}			// 10 개 정수를 배열 중 처음 3개가 값을 대입
[...]int{1,2,3}			// {} 안에 엘리먼트의 갯수로 결정되어 [3]int 배열이 된다.

* Swap

두 변수에 들어있는 값을 서로 맞바꾸는 연산인데, 다른 언어에서는 임시변수를 사용하지만 다음 코드로 된다.

i, j = j, i

* Slice

포인터 연산이 없는 대신 배열의 특정 부분을 참조하기 위해 사용.

var ar [10]int = [10]int{1,2,3,4,5,6,7,8,9,10}	// 배열 ar
var a []int		// 슬라이스 a

a = ar[7:9]		// ar 의 7,8 번째 값을 참조한다
len(a)			// a 의 사이즈는 2
a = ar[:n]		// ar[0:n] 배열의 0 번째부터 n-1 번째까지 참조한다.
a = ar[n:]		// ar[n:len(a)] 배열의 n 번째부터 끝까지를 참조한다.
a = ar[:]		// ar[0:len(ar)] 배열의 전체를 참조한다.

* defer 키워드

아래 코드는 Open -> ReadAll -> Close 순으로 호출된다. Open, Close 같이 열고 닫는 동작이 쌍으로 존재하는 경우 두 함수를 함께 붙여 사용할 수 있고, 마무리 동작을 잊지 않게 도와주는 효과가 있다.

func data(fileName string) string {
	f := os.Open(fileName)
	defer f.Close()
	contents := io.ReadAll(f)
	return contents
}

* 암시적 형변환(implicit type conversion)

var i16 int16
var i32 int32

// 암시적 형변환
i32 = i16

// 명시적 형변환
i32 = int32(i16)

type MyInt int
var i int
var j MyInt

func main() {
	i = 3
	j = 1			// 컴파일 에러
	j = MyInt(i)		// 반드시 명시적 형변환 필요
 ...
 }

* goroutine

goroutine 은 매번 커널 스레드를 생성하지 않고, 일부 커널 스레드로 멀티플렉싱되어 사용된다. goroutine 마다 하나의 스레드를 점유하는 방식이 아니라 동작하는 goroutine 이 멀티플렉스를 이용해 스레드에 할당되는 방식.

func doSomeThing() {
	...
}

func main() {
	go doSomeThing()
}

* 채널(channel)

두 goroutine 이 공유할 데이터가 있는 경우 채널을 통해 상대 goroutine 으로 데이터를 전달할 수 있다.

func main() {
	c := make(chan int)
    
    go func() {
    	...
        c<-1			// 채널 c 로 1 를 보낸다.
    }()
    <-c					// 채널 c 에서 값을 받아 사용하지 않고 버린다.
    fmt.Print("main End");
}

// 단항 연산자로 사용된 <- (receive)
v = <-c				// 채널 c 에서 값을 받아서 v 에 대입한다
i := <- c			// 채널 c 에서 값을 받고 이 값으로 i 를 초기화한다

※ 한빛미디어에서 나온 팝업북 형식의 "개발자를 위한 하룻밤에 읽는 Go 언어 이야기" (신제용 저) 읽고 나서 Go 언어에 관심이 더 생기게 되었다. 전자책 출판용으로 작성된 글이다 보니 코드 부분에서 오류가 조금 있고 설명이 대충 넘어가는 듯한 부분이 있어서 아쉽지만, 그래도 그동안 Go 언어를 대충 함수형 언어로만 생각하고 다음에 찾아보지 생각했었는데 이 책을 통해 Go 언어의 시작이 어떠했는지, 어떠한 용도로 나왔는지를 알 수 있는 책이었다.