Arrays

Go의 Array는 다른 언어들과 다르게 크기를 마음대로 조절할 수 있다. 

테스트

func main() {
	names := [5]string{"nico", "qazyj", "dal"}
	fmt.Println(names)
}

 

출력

일반적인 배열을 만드는 방법이다. 배열의 크기를 지정하고 배열안에 값을 넣어준다.

 

Slice

java에서의 List와 같은 느낌이 든다. slice라고 부르는데, append를 이용해서 사용할 수 있다.

배열의 크기를 지정하면 append를 사용할 수 없지만, 크기가 지정되어있지 않다면 append를 사용해서 크기를 마음대로 조절할 수 있다.

테스트

func main() {
	names := []string{"nico", "qazyj", "dal"}
	fmt.Println(names)
}

출력

위와 다르게 추가된 수 만큼 배열의 크기가 생성된다. append를 사용해보자

func main() {
	names := []string{"nico", "qazyj", "dal"}
	names = append(names, "test")
	fmt.Println(names)
}

출력

크기가 1만큼 증가하며 새로운 string이 추가된 것을 확인할 수 있다.

 

그렇다면, append는 어떻게 이루어져 있을까?

// The append built-in function appends elements to the end of a slice. If
// it has sufficient capacity, the destination is resliced to accommodate the
// new elements. If it does not, a new underlying array will be allocated.
// Append returns the updated slice. It is therefore necessary to store the
// result of append, often in the variable holding the slice itself:
//
//	slice = append(slice, elem1, elem2)
//	slice = append(slice, anotherSlice...)
//
// As a special case, it is legal to append a string to a byte slice, like this:
//
//	slice = append([]byte("hello "), "world"...)
func append(slice []Type, elems ...Type) []Type

builtin.go 라는 파일에 append는 위와같이 정의되어 있다. 설명을 보면 1개만 되는 것이 아닌 여러개가 한꺼번에 뒤로 추가해주는 것도 가능하다고 한다. 사용 방법은 배열 변수명 = append(배열 변수명, 추가하고싶은 element.....) 방법으로 사용하면 된다.

 

Java는 배열과 List가 있는 반면, Go의 경우 배열과 slice가 있다.

 

 

 

 

'Go' 카테고리의 다른 글

Struct  (0) 2024.01.04
Maps  (0) 2023.12.30
Pointer  (0) 2023.12.28
If/switch  (0) 2023.12.28
for, range, args  (0) 2023.12.28

Pointer

다른 변수, 혹은 그 변수의 메모리 공간주소를 가리키는 변수를 말한다

Test

func main() {
	a := 2
	b := a
	a = 10
	fmt.Println(a, b)
}

위와 같이 int type의 변수 a를 만들고, 만들어진 a를 b에 넣어준다. 그리고, a를 10으로 변경한다면 a와 b의 값은 어떻게 될까?

출력

정답은 a는 10으로 변경되지만, b의 값은 변경되지 않는다. 그렇다면, 가리키는 메모리 주소가 다르다는 것이다. Go에서는 C와 같이 메모리 주소를 보기 위해서는 &를 변수명 앞에 사용하면 된다. 

테스트

func main() {
	a := 2
	b := a
	a = 10
	fmt.Println(&a, &b)
}

출력

예상과 같이 주소값이 다르게 나온다. 근데, 이상한 점이 있다. 왜.. 2바이트 차이가 나는거지...? 내 예상대로라면 4바이트 차이가 나야한다. size를 확인해보면 8로 나온다. os가 64bit이기 때문에 int64를 사용하는 것 같은데, 왜 2바이트 차이가 나는걸까..? 

출력

같은 코드로 여러번 돌려보면 2차이가 있을 때도, 8차이가 있을 때도 존재한다. a의 크기는 8바이트이기 때문에 8차이가 나야되는게 맞는 것 같은데 이상하다. 시스템적인 문제인 것 같다. a의 값으로 9223372036854775807를 넣어줘도 같은 형상이 나타나기 때문이다. 일단, 넘어가자.

 

Pointer를 쓰고싶다면 c언어와 같은 방식으로 사용하면 된다. 변수에 주소값을 넣어주는 것이다.

테스트

func main() {
	a := 2
	b := &a
	a = 10
	fmt.Println(&a, b)
}

출력

a가 가리키는 주소값과 b의 값이 일치하는 것을 볼 수 있다. 값을 확인하기 위해서는 c언어와 같은 방식으로 사용하면된다.

테스트

func main() {
	a := 2
	b := &a
	a = 10
	fmt.Println(a, *b)
}

출력

b는 a주소를 가리키고 있기때문에, a의 값을 변경하면 b도 같이 바뀌는 것을 확인할 수 있다. 물론, b를 이용해서 값을 변경할 수도 있다.

테스트

func main() {
	a := 2
	b := &a
	*b = 10
	fmt.Println(a, *b)
}

출력

 

Pointer의 경우 C와 매우 같은 구조를 가지고있는 것을 볼 수 있다.

 

 

'Go' 카테고리의 다른 글

Maps  (0) 2023.12.30
Arrays/Slices  (0) 2023.12.29
If/switch  (0) 2023.12.28
for, range, args  (0) 2023.12.28
Functions  (0) 2023.12.28

If

다른 언어와 다르게 Go에서는 if 문 안에 variable을 만들 수 있다.

 

테스트

func main() {
	fmt.Print(canIDrink(16))
}

func canIDrink(age int) bool { 
	if koreanAge := age+2; koreanAge < 18 {
		return false
	}

	return true
	
}

예를들어, 위와같이 koreanAge라는 variable을 만들어서 조건문에 적용할 수 있다. 그때, variable을 만든 후 ;(세미콜론) 이후 사용하면 된다. 

	koreanAge := age+2			//...1
	if koreanAge < 18 {
		return false
	}
    
    	if koreanAge := age+2; koreanAge < 18 {			//...2
		return false
	}

 

위 두개의 코드는 같은 기능을 수행하는 코드이다. 하지만, 다른 사람이 보기에 1번의 코드에서 koreanAge는 if문 외에도 아래에서 더 사용하기때문에 따로 선언을 한 것처럼 보인다. 이를 방지하고자 2번과 같은 기능을 만든 것 같다.

 

switch

switch도 if문과 같이 variable을 생성해줄 수 있다.

테스트

func canIDrink(age int) bool {
	switch koreanAge := age+2; koreanAge {
	case 10:
		return false
	case 18:
		return true
	}

	return true
	
}

'Go' 카테고리의 다른 글

Arrays/Slices  (0) 2023.12.29
Pointer  (0) 2023.12.28
for, range, args  (0) 2023.12.28
Functions  (0) 2023.12.28
Variables/Constants  (0) 2023.12.27

반복문

Go에서 반복문은 오로지 for만 사용할 수 있다. Java는 for, while, map 등 반복문에 여러 기능이 가능했지만 Go에서는 for로만 사용 가능하다. 오히려 더 간편한 느낌이다.

 

테스트

func main() {
	fmt.Print(superAdd(1,2,3,4,5,6))
}

func superAdd(numbers ...int) int {
	sum := 0
	for index, number := range numbers {	// index(0,1...,n-1)와 number라는 index에 해당하는 값
		fmt.Println(index, number)
	}
	return sum
}

출력

물론, index가 필요하지 않은 경우 이전에 배웠던 _를 통하여 사용하지 않음을 명시해줄 수 있다. 

	for i:= 0; i< len(numbers); i++ {
		fmt.Println(i, numbers[i])
	}

java에서와 비슷한 방식으로 위와 같이도 사용이 가능하다.

 

'Go' 카테고리의 다른 글

Pointer  (0) 2023.12.28
If/switch  (0) 2023.12.28
Functions  (0) 2023.12.28
Variables/Constants  (0) 2023.12.27
Import/Export  (0) 2023.12.24

Concept

Basic Types

다른언어와 비슷하다.

  • string type
    • string
  • boolean type
    • bool
  • numeric types
    • int8, uint8, int16 .... int64, uint64, int, uint, uintptr
    • float32, float64
    • complext64, complex128

 

 

functions

파라미터로 int형 숫자 2개를 보내고 곱한 값을 Return하는 함수를 만들어보자.

func multiply(a int, b int) int {
	return a * b
}

 

Go에서의 함수는 왼쪽이 파라미터 명, 오른쪽이 타입이다. 또한, return이 있다면 () 오른쪽에 return type을 지정해주어야 한다. 아래처럼 파라미터의 타입이 모두 동일한 경우 맨 오른쪽에만 타입을 지정해줘도 된다. 

func multiply(a, b int) int {
	return a * b
}

 

또한, 여러 타입들을 한 번에 return 해올 수 있다. (Java에는 없었던 기능)

func getNameAndPhoneNumber() (string, int) {
	return "qazyj", 123456789
}

위와 같이 타입이 다른 변수 두개를 return할 수 있다.

func main() {
	name, number := getNameAndPhoneNumber()
	fmt.Print(name, number)
}

받는 방법은 위와같은 방법으로 받을 수 있다. 또한, return한 값을 사용하고 싶지 않을 때는 _를 사용하면 된다. (에러를 Return하는 경우  사용되지 않는 경우가 있기도 함.)

func main() {
	name, _ := getNameAndPhoneNumber()
	fmt.Print(name)
}

_를 하는 이유는 _를 하지않고 name만 return 받으려고 위와 같이 작성하면 에러가 발생한다. _는 무시되는 value로 컴파일 시에 무시된다.

 

functions에서 argument를 무제한으로 받을 수 있는 방법도 있다. type앞에 ...을 붙이면 된다.

func main() {
	repeatMe("q", "a", "z", "y", "j")
}

func repeatMe(words ...string) {
	fmt.Println(words)
}

출력

 

 

Naked Return

return 오른쪽에 return되는 값을 넣어주는 것이 아닌 Return Type을 적어주는 곳에 return 값을 넣음. 

 

사용 방법

func main() {
	fmt.Print(lenAndUpper("qazyj"))
}

func lenAndUpper(name string) (length int, uppercase string) {
	length = len(name)		// return 값에 선언해준 변수명이랑 같아야함
	uppercase = strings.ToUpper(name)     // return 값에 선언해준 변수명이랑 같아야함
	return // 필수
}

 

 

defer

function이 끝날 때, 추가적으로 무엇인가 동작할 수 있도록 하는 기능
Java에서 못봤던 기능인 것 같은데, 유용하게 쓰일 수 있는 기능 같다.
ex) 이미지를 열거나 파일을 생성하고나서 defer로 이미지, 파일을 닫던가 삭제하는, API로 요청을 보낸다던가 등

 

테스트

func lenAndUpper(name string) (length int, uppercase string) {
	defer fmt.Println("I am done.")			// ..1 
	fmt.Println("lengAndUpper Start")			// ..2
	length = len(name)
	uppercase = strings.ToUpper(name)
	fmt.Println("lengAndUpper Finish")			// ..3
	return
}

출력

defer라는 기능을 통해 1 -> 2 -> 3 번 순서로 출력이 되어야 할 출력물이, 2 -> 3 -> 1 번 순서로 출력되는 것을 볼 수 있다.

 

 

 

 

 

 

 

 

'Go' 카테고리의 다른 글

If/switch  (0) 2023.12.28
for, range, args  (0) 2023.12.28
Variables/Constants  (0) 2023.12.27
Import/Export  (0) 2023.12.24
package와 main  (0) 2023.12.24

Constants

상수를 만드는 방법은 간단하다.

const name = "qazyj"

위처럼 작성만 하면된다. 하지만, 아래처럼 아직 타입이 정해지지 않은 상수이다. 

Go는 type 언어이기 때문에 Java나 C처럼 type이 무엇인지 알려주어야 한다. 

const name string = "qazyj"

타입은 위와같이 작성해주면 된다. 당연하게도 string 대신 bool, int와 같은 타입은 작성해준다면 아래와 같은 에러를 발생해주며 코드 작성을 도와준다.

 

또한, 당연하게도 상수는 재할당을 할 수 없기때문에 할당을 하려는 코드를 작성하면 아래와 같은 에러 문구로 코드 작성을 도와준다.

 

 

Variables

contstants와 비슷하다. const를 var로만 바꾸면 된다. constants 때 사용한 코드에서 const -> var로만 변경해주었다.

constants와 다른 점은 재할당이 가능하다는 점에서 다르다.

 

하지만, 변수를 선언해줄 때의 코드가 너무 길다는 단점이 존재한다. 이러한 불편한 점을 Go 개발자들도 인지하였는지 아래와 같은 코드로도 작성이 가능하다.

name := "qazyj"

 

이게 뭐지 싶겠지만 name에 마우스 커서를 위치시켜 보면 아래와 같은 문구를 볼 수 있다. var와 type을 생략할 수 있도록 도와준다. :=를 사용하면 Go에서 자동으로 적절한 type을 설정해준다. 이를 부르는 용어는 Go의 짧은 변수 선언이라고 한다. 

그렇다면, 의문점이 생긴다. Go에서 선언된 값을 통하여 변수를 설정해주기 때문에 시간의 차이가 있지 않을까? 라는 생각이 들지만 알아본 바에 의하면 성능 차이는 거의 존재하지 않는다고 한다. var name string = "qazyj"는 지양하고, name := "qazyj"를 지향하면 보다 코드를 작성하는 시간을 단축시킬 수 있겠다.

 

 

 

 

'Go' 카테고리의 다른 글

for, range, args  (0) 2023.12.28
Functions  (0) 2023.12.28
Import/Export  (0) 2023.12.24
package와 main  (0) 2023.12.24
Go에서 의존성 주입 (wire, fx 사용방법)  (0) 2023.05.14

fmt와 같이 import해서 사용할 수 있는 func은 모두 대문자로 시작한다. 그냥 지나칠 수 있지만, 대문자로 시작하는 이유가 있다.

 

Java, python, node.js, JavaScript에서는 import 할 때 import XXX from XXX과 같은 방식으로 import 한다. Go는 function을 export하고 싶다면 function을 대문자로 시작해주면 된다.

 

Test
something이라는 폴더를 만들고 폴더안에 something.go 라는 go 파일을 하나 만들어 준다.

 

something.go 코드로는 아래와 같이 sayBye는 소문자로, SayHello는 대문자로 시작해주도록 했다.

package something

import "fmt"

func sayBye() {
	fmt.Println("Bye")
}

func SayHello() {
	fmt.Println("Hello")
}

 

그 후 

main에 위와 같이 import하여 func을 사용하면 대문자로 시작하는 func만 사용가능한 것을 볼 수 있다.

소문자로 시작하는 func의 경우 정의되어 있지않다는 문구를 볼 수 있다.

 

 

 

'Go' 카테고리의 다른 글

Functions  (0) 2023.12.28
Variables/Constants  (0) 2023.12.27
package와 main  (0) 2023.12.24
Go에서 의존성 주입 (wire, fx 사용방법)  (0) 2023.05.14
go로 gRPC Unary 찍먹  (0) 2023.05.01

Package

Go의 코드를 묶는 단위로 모든 .go 파일은 package를 설정해야 합니다.

가장 기본적으로 Go 파일을 컴파일하기 위해서는 프로그램의 시작점 Package를 main으로 설정해야 합니다.

 

 

main

  • packge main은 프로그램의 시작점입니다.
  • 그렇기때문에, package main으로 작성된 .go 파일은 해당 파일을 컴파일 할 것이고 시작 패키지는 packge main입니다.
  • package 명이 main이 아닌 패키지는 기능을 패키징화 한다는 등의 이유가 될 수 있습니다.

그렇다면, 위와같이 package만 작성하고 컴파일을 하면 컴파일러가 정상적으로 컴파일 할 수 있을까요?

그렇지 않습니다. 에러를 읽어보면 아래와 같은 runtime 에러 로그를 보여줍니다.

function main is undeclared in the main packge

 

main package 안에 function main이 선언되어있지 않다는 친절하고 명확한 에러로 개발을 편리하게 도와줍니다.

package main

func main() {
}

에러의 안내대로 위와 같이 func main() {}을 생성해주고 돌려보면 정상적으로 돌아갑니다. 이러한 경험대로 Go라는 언어는 컴파일 하기 위해서는 main package가 패키지의 시작점이고, main package안에서 func main() {}이 프로그램을 읽는 출발점이라고 볼 수 있습니다.

 

 

Go에서 제공하는 여러 package들은 아래에서 확인할 수 있다.

 

Standard library - Go Packages

Discover Packages Standard library Version: go1.21.5 Opens a new window with list of versions in this module. Published: Dec 5, 2023 License: BSD-3-Clause Opens a new window with license information. Jump to ... Directories Directories ¶ Show internal Exp

pkg.go.dev

 

 

 

 

 

 

'Go' 카테고리의 다른 글

Variables/Constants  (0) 2023.12.27
Import/Export  (0) 2023.12.24
Go에서 의존성 주입 (wire, fx 사용방법)  (0) 2023.05.14
go로 gRPC Unary 찍먹  (0) 2023.05.01
gRPC란?  (0) 2023.05.01

+ Recent posts