티스토리 뷰

나중에 제가 보기위해서 Go언어에 대한 문법과 사용 예제 및 관련 지식을 정리합니다.

우선 go언어의 키워드는 25가지입니다.

Keyworkds

         
break default func interface select
case defer go map struct
chan else goto package switch
const fallthrough if range type
continue for import return var

이번글에서는 위에 볼드체 되어있는 키워드들이 사용되었습니다.

또한 이번 글의 예제 목록은 다음과 같습니다.

  • Hello World
  • Values
  • Variables
  • Constants
  • For
  • If/Else
  • Switch
  • Arrays
  • Slices
  • Slice 자세히 알아보기

Hello World

package main
import "fmt"
func main() {
    fmt.Println("hello world")
}

Values

package main

import "fmt"

func main() {

    fmt.Println("go" + "lang")

    fmt.Println("1+1 =", 1+1)
    fmt.Println("7.0/3.0 =", 7.0/3.0)

    fmt.Println(true && false)
    fmt.Println(true || false)
    fmt.Println(!true)
}
$ go run values.go
golang
1+1 = 2
7.0/3.0 = 2.3333333333333335
false
true
false

일반적인 경우와 같습니다.
or 연산자 ||
and 연산자 &&

Variables

package main

import "fmt"

func main() {

    var a = "initial"
    fmt.Println(a)

    var b, c int = 1, 2
    fmt.Println(b, c)

    var d = true
    fmt.Println(d)

    var e int
    fmt.Println(e)

    f := "apple"
    fmt.Println(f)
}

var로 변수 선언

Constants

package main

import (
    "fmt"
    "math"
)

const s string = "constant"

func main() {
    fmt.Println(s)

    const n = 500000000

    const d = 3e20 / n
    fmt.Println(d)

    fmt.Println(int64(d))

    fmt.Println(math.Sin(n))
}

const로 상수 값 선언

For

package main

import "fmt"

func main() {

    i := 1
    for i <= 3 {
        fmt.Println(i)
        i = i + 1
    }

    for j := 7; j <= 9; j++ {
        fmt.Println(j)
    }

    for {
        fmt.Println("loop")
        break
    }

    for n := 0; n <= 5; n++ {
        if n%2 == 0 {
            continue
        }
        fmt.Println(n)
    }
}

Go는 While없이 반복문을 for로 통일하였는데, 사용법은 위와 같습니다.
단 ()없이 조건식을 선언해줍니다. continue도 사용 가능합니다.

If/Else

package main

import "fmt"

func main() {

    if 7%2 == 0 {
        fmt.Println("7 is even")
    } else {
        fmt.Println("7 is odd")
    }

    if 8%4 == 0 {
        fmt.Println("8 is divisible by 4")
    }

    if num := 9; num < 0 {
        fmt.Println(num, "is negative")
    } else if num < 10 {
        fmt.Println(num, "has 1 digit")
    } else {
        fmt.Println(num, "has multiple digits")
    }
}

()없이 조건식을 선언해줍니다. 일반적인 if, else if, else 사용법과 다르지 않습니다.
하지만 go에는 삼항연산자가 없습니다. (if로 대체하면 됨)

switch

package main

import (
    "fmt"
    "time"
)

func main() {

    i := 2
    fmt.Print("Write ", i, " as ")
    switch i {
    case 1:
        fmt.Println("one")
    case 2:
        fmt.Println("two")
    case 3:
        fmt.Println("three")
    }

    switch time.Now().Weekday() {
    case time.Saturday, time.Sunday:
        fmt.Println("It's the weekend")
    default:
        fmt.Println("It's a weekday")
    }

    t := time.Now()
    switch {
    case t.Hour() < 12:
        fmt.Println("It's before noon")
    default:
        fmt.Println("It's after noon")
    }

    whatAmI := func(i interface{}) {
        switch t := i.(type) {
        case bool:
            fmt.Println("I'm a bool")
        case int:
            fmt.Println("I'm an int")
        default:
            fmt.Printf("Don't know type %T\n", t)
        }
    }
    whatAmI(true)
    whatAmI(1)
    whatAmI("hey")
}

go에서는 switch에서 case에 조건식을 넣어 if를 대체하도록 사용이 가능합니다.
또한 마지막 스위치문 예시와 같이 데이터 타입에 따른 비교도 가능합니다. 변수는 t에 해당 하는 유형을 찾아서 실행됩니다.

Array

package main

import "fmt"

func main() {

    var a [5]int
    fmt.Println("emp:", a)

    a[4] = 100
    fmt.Println("set:", a)
    fmt.Println("get:", a[4])

    fmt.Println("len:", len(a))

    b := [5]int{1, 2, 3, 4, 5}
    fmt.Println("dcl:", b)

    var twoD [2][3]int
    for i := 0; i < 2; i++ {
        for j := 0; j < 3; j++ {
            twoD[i][j] = i + j
        }
    }
    fmt.Println("2d: ", twoD)
}

go언어에서는 Array배열보다는 slice가 일반적으로 사용됩니다.
array[index] = value로 값 설정 가능,
len은 배열의 길이를 반환합니다.

slice

package main

import "fmt"

func main() {

    s := make([]string, 3)
    fmt.Println("emp:", s)

    s[0] = "a"
    s[1] = "b"
    s[2] = "c"
    fmt.Println("set:", s)
    fmt.Println("get:", s[2])

    fmt.Println("len:", len(s))

    s = append(s, "d")
    s = append(s, "e", "f")
    fmt.Println("apd:", s)

    c := make([]string, len(s))
    copy(c, s)
    fmt.Println("cpy:", c)

    l := s[2:5]
    fmt.Println("sl1:", l)

    l = s[:5]
    fmt.Println("sl2:", l)

    l = s[2:]
    fmt.Println("sl3:", l)

    t := []string{"g", "h", "i"}
    fmt.Println("dcl:", t)

    twoD := make([][]int, 3)
    for i := 0; i < 3; i++ {
        innerLen := i + 1
        twoD[i] = make([]int, innerLen)
        for j := 0; j < innerLen; j++ {
            twoD[i][j] = i + j
        }
    }
    fmt.Println("2d: ", twoD)
}

Go의 중요한 데이터 유형이라고 합니다.
배열과 달리 슬라이스는 포함된 요소에 의해서만 유형이 지정됩니다. 길이가 0이 아닌 빈 슬라이스를 만들려면 go언어의 내장함수은 make()함수를 이용합니다.

make() 함수는 "make(슬라이스 타입, 슬라이스 길이, 슬라이스의 용량)" 형태로 선언 됩니다.
여기서 용량(Capacity)은 생략해서 선언할 수 있는데, 용량을 생략하면 슬라이스의 길이와 똑같은 값으로 선언 됩니다.

s := make([]string, 3)

슬라이스를 한번 생성하면, 인덱스에 값을 대입하는것은 배열과 같습니다.

    s[0] = "a"
    s[1] = "b"
    s[2] = "c"

append로 slice에 값을 더할 수도 있습니다.

    s = append(s, "e", "f")

copy도 가능합니다.

    copy(c, s)

c에서는 s와 같은 길이의 slice를 만들고 s를 c에 복사합니다.

slice는 슬라이스 연산자도 지원합니다.

    l := s[low:high]

low부터 hight까지의 값을 출력해줍니다.
low를 생략하면 0부터, high까지
high를 생략하면 low 부터 마지막 index까지 슬라이스한 새로운 슬라이스를 반환합니다.

    t := []string{"g", "h", "i"}

슬라이스에 대한 변수를 한 줄로 선언하고 초기화하는 방법입니다.

Slice 자세히 알아보기

슬라이스는 배열과 유형이 다르지만 유사하게 렌더링된다고 합니다.
가장 큰 차이는 배열은 선언과동시에 배열의 크기가 정해지지만, 슬라이스는 동적으로 크기가 할당된다는 것입니다.
또한 배열과 달리 레퍼런스 타입입니다. 내부적으로는 배열을 통해서 값을 관리하며, slice 자체는 배열의 가장 첫번째 요소를 가리키는 포인터를 담게 되는데 이 때문에 생성된 슬라이스를 새로운 변수에 대입한 후 대입한 변수에서 슬라이스의 특정 인덱스값을 수정하게 되면, 원래 슬라이스의 값도 변경되게 됩니다.

그래서 같은 슬라이스의 복사본을 자유롭게 활용하고 싶다면 copy()함수를 통해서 사용해야 합니다.
slice에는 용량이라는 개념이 있습니다. slice가 용량만큼 가득 차게 되면 미리 메모리 공간을 확보해 놓는 것입니다. (c++의 vector 개념과 유사하다.) cap 명령어를 사용하여 현재 용량을 확인할 수 있습니다.

cap(slice)를 통해서 확인할 수 있는건데..
직접 확인해보니 len과 cap이 다른값이 나옵니다.
예를들어

package main

import "fmt"

func main() {
    s := []int{2, 3, 5, 7, 11, 13}
    printSlice(s)

    // Slice the slice to give it zero length.
    s = s[:0]
    printSlice(s)

    // Extend its length.
    s = s[:4]
    printSlice(s)

    // Drop its first two values.
    s = s[2:]
    printSlice(s)

    s = append(s, 1, 2, 3, 4, 5, 2, 4, 7, 9, 8, 0)
    printSlice(s)

    t := []int{2, 3, 5, 7, 11}
    printSlice(t)
}

func printSlice(s []int) {
    fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s)
}

의 결과값은

len=6 cap=6 [2 3 5 7 11 13]
len=0 cap=6 []
len=4 cap=6 [2 3 5 7]
len=2 cap=4 [5 7]
len=13 cap=14 [5 7 1 2 3 4 5 2 4 7 9 8 0]
len=5 cap=5 [2 3 5 7 11]

입니다.
cap이 slice초기값 선언시에는 len과 같지만, 이후에는 slice에 값을 추가하거나 삭제했을 때 용량이이 늘어나기도 하고, 줄어들기도 하는것을 확인할 수 있습니다.

slice의 용량은 미리 할당된 메모리를 뜻한다고 합니다. 그래서 값을 추가하다가 slice가 메모리를 다 쓰게 되면, 이후에 추가할때는 여유메모리를 값을 추가한 만큼이 아닌, 미리 더 가져오는것을 확인할 수 있었습니다.

https://go-tour-ko.appspot.com/moretypes/11

 

Go를 향한 여행

 

go-tour-ko.appspot.com

위 페이지에서 간단하게 직접 실험 가능합니다.


글의 내용은

https://gobyexample.com/
[https://go.dev/ref/spec#Keywords]

Go언어 공식 홈페이지 중 위 두 페이지를 참고하였습니다.

댓글
최근에 올라온 글
최근에 달린 댓글
250x250