[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)
}