[Go]Golang 개본개념
Go 파일 이해하기
Go 파일의 특징
- 컴파일을 하기 위해서는 main.go가 필요하다.
- Go 파일은 package를 선언해줘야 한다.
- 컴파일시에 function을 찾아간다.(없으면 오류)
Go 파일의 구성
package main import "fmt" // fmt 사용시 자동 생성, 사용하지 않을 시에 자동 제거(vscode) func main() { fmt.Println("Hello World!") }
fmt : Go가 내장하고 있는 패키지
Go 파일 실행
go run 파일명.go
export와 import
function 이름이 대문자로 시작하면 public
function 이름이 소문자로 시작하면 private
package main import ( "fmt" // fmt 사용시 자동 생성 "github.com/saichoi/learngo/someting" // someting 사용시 자동 생성 ) func main() { fmt.Println("Hello World!") someting.SayHello() someting.sayBye() // private 사용하면 에러남 }
package someting import "fmt" // Private 함수 func sayBye() { fmt.Println("Bye") } // Public 함수 func SayHello() { fmt.Println("Hello") }
변수(Variables)와 상수(Constants)
변수 : 값 변경 가능(JS의 let)
상수 : 값 변경 불가능(JS의 const)
Go는 Type 언어로 해당 변수가 어떤 타입인지 알려줘야하는 언어이다. 하지만 func 내부에서는 Go가 타입을 추론해준다.
package main import "fmt" func main() { // 타입이 없는 상수 (Constant) const name1 = "dahye" // 타입이 있는 상수(Constant) const name2 string = "dahye" // 타입이 없는 변수 (Variables) var age1 = 30 // 미사용시 에러 fmt.Println(age1) // 타입이 있는 변수 (Variables) var age2 int = 25 // 미사용시 에러 fmt.Println(age2) // 축약형 (func 내부에서만 사용 가능) name3 := "dahye" // 미사용시 에러 fmt.Println(name3) age3 := 17 // 미사용시 에러 fmt.Println(age3) // 값변경이 불가능한 상수 name1 = "choi" // 에러 name2 = "choi" // 에러 // 값변경이 가능한 변수 age1 = 21 age2 = 34 age3 = 13 }
Go 언어의 타입
타입 | 종류 |
string type | string |
bool type | bool |
numeric types | int8, unit8(byte), int16, unit16,(rune), unit32, int64, unit64, int, unit, unitptr, float32, float64, complex64, complex128 |
함수(Function)
1. 리턴 타입 명시
Go에서는 변수는 물론 함수에도 return 타입을 알려줘야한다.
func 함수명(인수 인수타입) 함수타입{ 실행코드 }
package main import "fmt" // 숫자 타입의 인수 a, b를 받아 a * b를 반환하는 함수 func multipy(a int, b int) int { return a * b } func main() { fmt.Println(multipy(2, 2)) }
2. 복수의 리턴값
Go에서는 함수가 여러개의 값을 return 할 수 있다.
package main import ( "fmt" "strings" ) // 이름을 받아 -> 이름의 길이를 세고 이름을 대문자로 변환하는 함수 func lenAndUpper(name string) (int, string) { return len(name), strings.ToUpper(name) } func main() { totalLenght, upperName := lenAndUpper("dahye") fmt.Println(totalLenght, upperName) } // _(underscore)로 value 무시 func main() { totalLenght, _ := lenAndUpper("dahye") fmt.Println(totalLenght) }
3. 복수의 인수값
Go에서는 원하는 만큼 함수의 인수를 받을 수 있다.
package main import "fmt" // 받아온 여러개의 인수를 모두 출력하는 함수 func repeatMe(words ...string) { fmt.Println(words) } func main() { repeatMe("dahye", "dayeon", "minsu", "jaewook") }
4. naked return
return 값이 명시되지 않을 경우 변수가 같은 값을 자동으로 return 해준다.
package main import ( "fmt" "strings" ) // 이름을 받아 -> 이름의 길이를 세고 이름을 대문자로 변환하는 함수 func lenAndUpper(name string) (lenght int, uppercase string) { lenght = len(name) uppercase = strings.ToUpper(name) return // 변수가 같은 값을 자동으로 리턴해준다. } func main() { totalLenght, upperName := lenAndUpper("dahye") fmt.Println(totalLenght, upperName) }
5. defer
함수 종료 후에 추가적으로 동작할 수 있도록 해주는 기능이다.
package main import ( "fmt" "strings" ) func lenAndUpper(name string) (lenght int, uppercase string) { // lenAndUppder 함수가 실행된 후에 추가적으로 코드가 실행된다. defer fmt.Println("I'm done.") lenght = len(name) uppercase = strings.ToUpper(name) return } func main() { totalLenght, upperName := lenAndUpper("dahye") fmt.Println(totalLenght, upperName) }
반복문(Loop)
1. for / range
range는 변수 안의 값을 하나씩 가져오는 역할을 하며 기본적으로 index 값을 가진다. index 사용하지 않는 경우 _(undersocore)로 대신할 수 있다.
package main import "fmt" func superAdd(numbers ...int) int { for index, number := range numbers { fmt.Println(index, number) } return 1 } func main() { superAdd(1, 2, 3, 4, 5, 6) }
2. for
()가 없는 for 반복문으로 작성할 수 있다.
package main import "fmt" func superAdd(numbers ...int) int { for i := 0; i < len(numbers); i++ { fmt.Println(numbers[i]) } return 1 } func main() { superAdd(1, 2, 3, 4, 5, 6) }
예제
package main import "fmt" // 들어온 인자의 값을 전부 더하는 함수 func superAdd(numbers ...int) int { total := 0 for _, number := range numbers { // index를 사용하지 않기 위해 _로 대체 total += number } return total } func main() { result := superAdd(1, 2, 3, 4, 5, 6) // 함수에 여러개의 인자를 넣음 fmt.Println(result) }
조건문
1. if
()가 없는 if 조건문을 사용할 수 있다.
package main import "fmt" func canIDrink(age int) bool { if age < 18 { return false } else { return true } } func main() { fmt.Println(canIDrink(18)) }
variable expression
조건문 내에서만 사용하는 변수를 생성할 수 있다.
package main import "fmt" func canIDrink(age int) bool { if koreanAge := age + 2; koreanAge < 20 { return false } return true } func main() { fmt.Println(canIDrink(17)) }
2. switch
package main import "fmt" func canIDrink(age int) bool { switch { case age < 18: return false case age == 18: return true case age > 50: return false } return false } func main() { fmt.Println(canIDrink(18)) }
variable expression
조건문 내에서만 사용하는 변수를 생성할 수 있다.
package main import "fmt" func canIDrink(age int) bool { switch koreaAge := age + 2; { case koreaAge < 20: return false case koreaAge == 20: return true case koreaAge > 50: return false } return false } func main() { fmt.Println(canIDrink(18)) }
Pointers
메모리에 접근하여 메모리 주소와 저장된 값을 볼 수 있다. 이 방법을 이용하여 같은 값을 공유하는 것으로 메모리 저장 공간을 줄여주고 실행 속도를 빠르게 할 수 있다.
&
: 메모리 주소 보는 법
*
: 메모리 안의 값을 살펴보는 법
package main import "fmt" func main() { // a의 복사본을 만들면 같은 메모리의 값을 공유하는 것이 아니라 새로운 메모리에 똑같은 값을 넣게 된다. a := 2 b := a a = 10 a = 12 fmt.Println(a, b) // 12 2 -> 아무리 a의 값을 변경하여도 a 값을 복사한 값을 가진 b의 값은 아무런 영향을 주지 않는다. // 메모리 주소 보는 방법 fmt.Println(&a, &b) // 0xc0000b2008 0xc0000b2010 -> 주소가 다른 것을 확인할 수 있다. }
package main import "fmt" func main() { a := 2 b := &a // b에 a의 메모리를 저장 fmt.Println(a, b) // 2 0xc0000b2008 -> 값과 메모리 주소를 확인 할 수 있다. // 메모리 안을 살펴보는 방법 fmt.Println(*b) // 2 -> b에 저장된 값이 a의 값과 같다는 것을 확인할 수 있다. }
package main import "fmt" func main() { a := 2 b := &a // b에 a의 메모리를 저장 a = 5 fmt.Println(*b) // 5 -> a의 값을 공유하고 있는 b의 값도 함께 변경되는 것을 확인할 수 있다. }
package main import "fmt" func main() { a := 2 b := &a *b = 20 // a의 메모리 주소를 공유하는 b의 값을 변경할 수 있다. fmt.Println(a) // 20 -> a는 b와 값을 공유하기 때문에 b의 값이 변경되면 a의 값도 변경된다. }
Arrays & Slices
Arrays
만들어둔 배열의 개수만큼 값을 넣을 수 있다.
package main import "fmt" func main() { names := [5]string{"dahye", "dayeon", "minsu"} names[3] = "lalala" names[4] = "lululu" names[5] = "nonono" // 정해진 배열의 크기 만큼만 넣을 수 있기 때문에 에러가 난다. fmt.Println(names) }
Slices
배열의 개수 제한 없이 값을 넣을 수 있다.
package main import "fmt" func main() { // slice는 array에서 길이를 넣지 않은 것이다. names := []string{"dahye", "dayeon", "minsu"} // slice 배열에 값 추가하는 법 // slice는 array와 같지만 값을 추가하는 방법은 다르다. // names[3] = "lalala" // -> 이렇게 하면 에러남 names = append(names, "lalala") fmt.Println(names) }
Maps
Go에서 map은 key와 value를 지정할 때 타입을 알려줘야한다.
package main import "fmt" func main() { // key와 value에 타입을 지정한다. 첫번째 string은 key의 타입, 두번째 string은 value의 타입이다. dahye := map[string]string{"name": "dahye", "age": "20"} fmt.Println(dahye) // 반복문으로 map 출력하기 for key, value := range dahye { fmt.Println(key, value) } // key를 제외하고 value만 출력 for _, value := range dahye { fmt.Println(value) } // value를 제외하고 key만 출력 for key, _ := range dahye { fmt.Println(key) } }
초기화되지 않은 map에 값을 할당할 수 없다. 초기화 하지 않은 map은 nil이 된다.
// map 초기화하는 방법 var results = map[string]string{} var results = make(map[string]string)
Structs(구조체)
Go에서는 자바의 class, python과 JS의 object 대신에 structs(구조체)를 사용한다. 또한 다른 언어와 달리 method와 constructor가 존재하지 않기 때문에 직접 constructor를 실행해야한다.
package main import "fmt" // 구조체 만드는 법 type person struct { name string age int favFood []string // string 타입의 slice } func main() { favFood := []string{"tteokbokki", "sushi"} // dahye := person{"dahye", 30, favFood} dahye := person{name: "dahye", age: 30, favFood: favFood} // key : value를 더욱 직관적으로 볼 수 있다. fmt.Println(dahye) }