Golang

GO 정리

dlwltn98 2023. 2. 12. 10:32
  • 컴파일을 하려면 main.go의 이름 변경 불가
  • 목적에 따라 컴파일을 할 필요가 없다면 main.go 사용하지 않아도 괜찮음

        - 컴파일 할 필요가 없는 경우 : 오픈소스 기여, 라이브러리 개발...

 

main.go

 - 컴파일을 위해 필요

 - 컴파일러는 main package와 그 안에 있는 main func을 먼저 찾고 실행시킴

// 내가 어떤 패키지를 사용하는지 작성해줘야 함
package main

// 프로그램의 시작점이 되는 부분
func main() {
    ...
}

 

go의 구성

 - Package declaration 

 - Import packages

 - Functions

 - Statements and expressions

 

Package and Import

package main

// formatting을 위한 패키지, 텍스트 출력/인쇄에 사용
import "fmt"

func main() {
    fmt.Println("Hello World")
}

 - go에서는 모든 프로그램이 패키지의 일부임

 - go의 문장은 행 끝(enter) or 세미콜론(;)으로 구분

   (enter 누르면 암묵적으로 ; 사용, 소스에는 표시 x)

 - { 는 문장의 선두에 올 수 없음

func main()
{   // Error 발생
fmt.Println("Hello World!")
}

 

변수와 상수

상수

 - 변수지만 값을 바꿀 수 없음

 - JS와 비교 : const

package main

func main() {
    // 아래와 같이 선언시 타입이 없는 상수가 선언됨
	const name = "jisu"
}

Untyped constants

package main

func main() {
	const name string = "jisu"  // 상수
}

Typed constants

 

변수

 - 말 그대로 변수,  값 변경 가능

 - JS와 비교 : let

 - type : int / uint8 / float32 / complex64 / string / bool ... (다양함)

 - 변수 선언 방법 

 

1. var 키워드 사용

// var 변수이름 type = 값
var name string = "jisu"  // 변수

2. := 기호 사용

// 변수이름 := 값
name := "jisu"

 - 기호를 사용하면 값을 통해 타입을 추론 (컴파일러가 타입 결정)

 - 정해진 타입은 내가 임의로 변경 불가

 - 기호는 오로지 func안에서만 사용 가능하고 변수에서만 적용 가능

 

var와 := 의 차이점

var :=
func의 안 또는 밖 어디서든 사용 가능 func 안에서만 사용 가능
함수 선언과 값 할당 별도로 가능 
(함수 선언 먼저 하고 나중에 값 할당 가능)
함수 선언과 값 할당 별도로 불가능
(함수 선언과 값 할당을 같은 라인해서 해야함)

 

 

초기값이 없는 변수 선언

 - 모든 변수가 초기화 됨

 - 초기값을 지정하지 않고 변수를 선언하면 기본값으로 설정 됨

func main() {
    var a string
    var b int
    var c bool
    
    fmt.Println(a)  // ""
    fmt.Println(b)  // 0
    fmt.Println(c)  // false
}

 

다중 변수 선언

 - 여러 변수를 한 줄에 선언 가능

var a, b, c, d int = 1, 3, 5, 7

 

블록 변수 선언

 - 여러 변수 선언을 블록으로 그룹화 가능

var (
a int
b int = 1
c string = "hello"
)

 

Functions

 - 페이지가 로드될 때 자동으로 실행되지 않고 호출에 의해 실행 됨

func 함수이름 { ... }
package something

import "fmt"

// private 함수, 호출 안됨
func sayBye() {
	fmt.Println("Bye")
}

// 호출 가능
func SayHello() {
	fmt.Println("Hello")
}

 - 첫 문자가 소문자로 이름이 지어진 함수는 private

    sayBye() : 다른 패키지에서 호출 불가능

    SayHello() : 다른 패키지에서 호출 가능

 - 첫 문자가 대문자로 작성된 함수는 다른 패키지로부터 호출된 함수라고 봐도 됨

 

 

Parameters

func mul(a int, b int) {
	fmt.Println( a * b )
}

// 파라미터의 타입이 같다면 아래와 같이 사용 가능
func mul(a, b int) {
	fmt.Println( a * b )
}

 - 원하는 만큼 파라미터를 전달하는 방법

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

func main() {
    repeatMe("jisu", "lee", "ji", "su")
}

// result, array 형태로 나옴
[jisu lee ji su]

 

반환값 (Returns)

 - 반환값이 있을때 반환형을 알려줘야함

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

 - 여러개의 반환값을 가질 수도 있음

// 반환 값이 int, string 2개임
func lenAndUpper(name string) (int, string) {
	return len(name), strings.ToUpper(name)
}

 

ignored value

 - _ 는 무시된 value → 컴파일할때 무시함

// 두개의 값을 반환하는 함수에서 값을 하나만 받으면 Error 발생
func lenAndUpper(name string) (int, string) {
	return len(name), strings.ToUpper(name)
}

func main() {
	totalLength := lenAndUpper("jisu")  // Error
	fmt.Println(totalLength, upperName)
}

// value 값을 무시하는 코드를 작성하면 Error 사라짐
func main() {
	totalLength, _ := lenAndUpper("jisu")
	fmt.Println(totalLength, upperName)
}

 

naked returns

 - 값을 반환하는 또다른 방법

 - return 할 변수를 명시 안해도 됨

func lenAndUpper(name string) (length int, uppercase string) {
    // = 을 쓰는 이유는 length, uppercase를 업데이트 하고 있기 때문
    length = len(name)
    uppercase = strings.ToUpper(name)
    return
}

 

defer

 - func 끝났을때 추가적으로 무엇인가 동작하도록 할 수 있음

func lenAndUpper(name string) (length int, uppercase string) {
    defer fmt.Println("I'm done")  // func 끝나고 나서 실행 됨
    length = len(name)
    uppercase = strings.ToUpper(name)
    return
}

 

for, range, ... args

 - 반복문은 for만 사용 가능

 - range : index를 줌, for 안에서 적용 가능

func superAdd(numbers int) int {
// numbers안에서 조건에 따라 반복실행을 하도록 해줌
    for number := range numbers {
        fmt.Println(number)
    }
    return 1
}

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

// result
0
1
2
3
4
5
func superAdd(numbers int) int {
    // 첫번째는 인덱스, 두번째는 값
    for _, number := range numbers {
        fmt.Println(number)
    }
    return 1
}

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

// result
1
2
3
4
5
6
// 아래와 같이도 가능
for i:=0; i < len(numbers); i++ {
    fmt.Println(numbers[i])
}

// result
1
2
3
4
5
6

 

if with a twist

package main

import "fmt"

func canIDrink(age int) bool {
	if age < 18 {
		return false
	}
	return true
}

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

 + variable expression

 - if를 쓰는 순간에 변수 생성 가능

func canIDrink(age int) bool {
    // if else 조건에서만 사용하기위해 변수 생성
	if koreanAge := age+2; koreanAge < 18 {
		return false
	}
	return true
}

// 위 코드는 아래 코드와 같은거임
func canIDrink(age int) bool {
  koreanAge := age+2
	if koreanAge < 18 {
		return false
	}
	return true
}

 

Switch 

switch {
case age < 18 : 
    return false
case age == 18 : 
    return true
case age > 50 : 
    return false
}

 + variable expression

switch koreanAge := age + 2; koreanAge {
case 10 : 
    return false
case 18 : 
    return true
}

 

 

Pointers

 - Low level programming

 - 메모리로 접근해서 메모리의 주소 볼 수 있음

 - 메모리 주소에 저장된 값도 볼 수 있음

func main() {
    a := 2
    b := a  // 값이 복사됨
    a = 10
    fmt.Println(a, b)
}

// result
10 2
// 값이 복사되는걸 원하지 않는 경우 , 실제로 원하는 값: 메모리 주소
func main() {
    a := 2
    b := 5
    fmt.Println(&a, &b)  // 메모리 주소 출력
}
// 위 코드와 같은 결과 나옴
func main() {
    a := 2
    b := &a
    fmt.Println(&a, b)  
}

 - & : Address

 - * : Pointer

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

// result 
2
func main() {
    a := 2
    b := &a
    a = 5
    fmt.Println(*b) 
}

// result 
5
// b는 a의 메모리 주소에 연결되어 있음
// 그래서 a가 바뀌면 같이 바뀜
func main() {
    a := 2
    b := &a  // b는 a를 살펴보는 pointer
    *b = 20
    fmt.Println(a)  
}

// result 
20
//  b는 a의 주소를 가지고 있기 때문에 a의 값을 바꿀 수 있음

 

Arrays

 - 동일한 유형의 여러 값을 단일 변수에 저장하는데 사용

 - 선언 방법

1. var 키워드

// var 배열명 = [길이]데이터 타입 { 값 }
func main() {
    var name = [5]string{"jisu", "lee", "ji"}
    name[3] = "lalala"
    name[4] = "lalala"
    name[5] = "lalala"   // Error
    fmt.Println(name)
}

2. := 기호

// 배열명 := [길이]데이터 타입 { 값 }
func main() {
    name := [5]string{"jisu", "lee", "ji"}
    name[3] = "lalala"
    name[4] = "lalala"
    name[5] = "lalala"   // Error
    fmt.Println(name)
}

 - 배열 초기화

// 초기화 되지 않은 경우 지정된 타입의 기본값이 할당 됨
arr1 := [5]int{} //not initialized
arr2 := [5]int{1,2} //partially initialized

// result
[0 0 0 0 0]
[1 2 0 0 0]

 - len() : 배열 길이

arr1 := [4]string{"Volvo", "BMW", "Ford", "Mazda"}
fmt.Println(len(arr1))

// result
4

 

Slices

 - 동일한 유형의 여러 값을 단일 변수에 저장하는데 사용

 - 배열과 비슷하지만 더 강력하고 유연함

 - 길이를 필요에 따라 늘리거나 줄일 수 있음

// 슬라이스명 := []데이터 타입 { 값 }
myslice1 := []int{}
myslice2 := []int{1,2,3}

 - 배열 슬라이스

// 배열을 슬라이스하여 슬라이스 생성 가능
arr1 := [6]int{10, 11, 12, 13, 14,15}
myslice := arr1[2:4]  // [12, 13]

 - append() : 슬라이스에 아이템 추가

func main() {
    names := []string{"jisu", "lee", "ji"}
    // 2개의 인자를 요구함 1: slice, 2: 추가할 값
    append(names, "lalala")
    fmt.Println(names[2])
}

 - len() : 슬라이스의 길이 (요소의 수) 반환

 - cap() : 슬라이스의 용량 반환 (늘리거나 줄일 수 있는 요수의 수)

myslice := []string{"Go", "Slices", "Are", "Powerful"}
fmt.Println(len(myslice))  // 4
fmt.Println(cap(myslice))  // 4

 

Maps

 - key : value 로 값 저장

 - 중복 x, 순서 x

func main() {
    // map 생성, key=string, value=string
    jisu := map[string]string{"name":"jisu", "age":"7"}
    fmt.Println(jisu)
}

// result
map[age:12 name:jisu]

 - 추가

// 맵이름[key] = value
jisu["year"] = "1998"

 - 삭제

// delete(맵이름, key)
delete(jisu, "year")

 - 특정 값 찾기

// val, ok := 맵이름[key]
val, ok := jisu["name"]  // jisu true
val2, ok2 := jisu["aa"]  // false

 * val : 값 

 * ok : 키가 존재하면 true, 키가 없으면 false

 

 - range

func main() {
    jisu := map[string]string{"name":"jisu", "age":"7"}
    for key, value := range jisu {
        fmt.Println(key, value)
    }
}

// result
name jisu
age 7

 

Structs

 - 서로 다른 데이터 유형의 멤버 집합을 변수로 만드는데 사용

 - 데이터를 그룹화하여 레코드 작성 가능

 - type, struct 키워드 사용

type person struct {
    // 안에는 구조체의 형태를 만들어주면 됨
    name string
    age int
    favFood []string
}

func main() {
    favFood := []string{"rice", "kimchi"}
    // 1. 순서대로 기입
    jisu := person{"leejisu", 7, favFood }
    fmt.Println(jisu)
    fmt.Println(jisu.name)
}

// result
{leejisu7 [rice jimchi]}
leejisu
// 이렇게도 작성 가능
func main() {
    favFood := []string{"rice", "kimchi"}
    // 2. 위 코드보다 명확하게 알아보기 쉬움
    jisu := person{name: "leejisu", age: 7, favFood: favFood}
    fmt.Println(jisu)
}

 

 

 

출처 :

https://www.w3schools.com/go/index.php

https://nomadcoders.co/go-for-beginners/lobby

'Golang' 카테고리의 다른 글

간단한 Job Scrapper 구현  (2) 2023.02.14
golang을 이용한 간단한 실습  (1) 2023.02.13