[ Go ] Go 언어 기본 문법 (2)

 
by 박신종



기본 자료형

Go의 기본 자료형은 아래와 같습니다.

자료형 저장범위 설명
uint8 0 ~ 255 부호 없는 8비트 정수형
uint16 0 ~ 65,535 부호 없는 16비트 정수형
unit32 0 ~ 4,294,967,295 부호 없는 32비트 정수형
uint64 0 ~ 18,446,744,073,709,551,615 부호 없는 64비트 정수형
uint   32비트 시스템에서는 uint32, 64비트 시스템에서는 uint64
int8 -128 ~ 127 부호 있는 8비트 정수형
int16 -32,768 ~ 32,767 부호 있는 16비트 정수형
int32 -2,147,483,648 ~ 2,147,483,647 부호 있는 32비트 정수형
int64 -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807 부호 있는 64비트 정수형
int   32비트 시스템에서는 int32, 64비트 시스템에서는 int64
float32   IEEE-754 32비트 부동소수점, 7자리 정밀도
float64   IEEE-754 64비트 부동소수점, 12자리 정밀도
complex64   float32 크기의 실수부와 허수부로 구성된 복소수
complex128   float64 크기의 실수부와 허수부로 구성된 복소수
uintptr   uint와 같은 크기를 갖는 포인터형
bool   참, 거짓을 표현하기 위한 8비트 자료형
byte   8비트 자료형
rune   유니코드 저장을 위한 자료형, 크기는 int32와 동일
string   문자열을 저장하기 위한 자료형
var (
    ToBe   bool       = false
    MaxInt uint64     = 1<<64 - 1
    z      complex128 = cmplx.Sqrt(-5 + 12i)
)

func main() {
    const f = "%T(%v)\n"
    fmt.Printf(f, ToBe, ToBe)
    fmt.Printf(f, MaxInt, MaxInt)
    fmt.Printf(f, z, z)
}

#bool(false)
#uint64(18446744073709551615)
#complex128((2+3i))



구조체 (Structs)

struct 는 필드(데이터)들의 조합입니다.

type Vertex struct {
    X int
    Y int
}

func main() {
    fmt.Println(Vertex{1, 2})
}

#{1 2}



구조체 필드

구조체에 속한 필드(데이터)는 dot(.) 으로 접근합니다.

type Vertex struct {
    X int
    Y int
}

func main() {
    v := Vertex{1, 2}
    v.X = 4
    fmt.Println(v.X)
}

#4



포인터 (Pointers)

Go에는 포인터가 있지만 포인터 연산은 불가능합니다.

구조체 변수는 구조체 포인터를 이용해서 접근 할 수 있습니다.

포인터를 이용하는 간접적인 접근은 실제 구조체에도 영향을 미칩니다.

type Vertex struct {
    X int
    Y int
}

func main() {
    p := Vertex{1, 2}
    q := &p
    q.X = 1e9
    fmt.Println(p)
}
# {1000000000 2}



구조체 리터럴 (Struct Literals)

구조체 리터럴은 필드와 값을 나열해서 구조체를 새로 할당하는 방법입니다.

원하는 필드를 {Name: value} 구문을 통해 할당할 수 있습니다. (필드의 순서는 상관 없습니다.)

특별한 접두어 & 를 사용하면 구조체 리터럴에 대한 포인터를 생성할 수 있습니다.

type Vertex struct {
    X, Y int
}

var (
    p = Vertex{1, 2}  // has type Vertex
    q = &Vertex{1, 2} // has type *Vertex
    r = Vertex{X: 1}  // Y:0 is implicit
    s = Vertex{}      // X:0 and Y:0
)

func main() {
    fmt.Println(p, q, r, s)
}
#{1 2} &{1 2} {1 0} {0 0}



new 함수

new(T) 는 모든 필드가 0(zero value) 이 할당된 T 타입의 포인터를 반환합니다.

( zero value 는 숫자 타입에서는 0 , 참조 타입에서는 nil 을 뜻합니다 )

var t *T = new(T)

또는

t := new(T)

위의 변수 t는 T 에서 반환된 포인터를 가집니다.

type Vertex struct {
    X, Y int
}

func main() {
    v := new(Vertex) // var v *Vertex = new(Vertex)
	
    fmt.Println(v)
    v.X, v.Y = 11, 9
    fmt.Println(v)
}

# &{0 0}
# &{11 9}



슬라이스 (Slices)

슬라이스는 배열의 값을 가리킵니다(point). 그리고 배열의 길이를 가지고 있습니다.

[]T 는 타입 T 를 가지는 요소의 슬라이스(slice) 입니다.

func main() {
    p := []int{2, 3, 5, 7, 11, 13}
    fmt.Println("p ==", p)

    for i := 0; i < len(p); i++ {
        fmt.Printf("p[%d] == %d\n",
            i, p[i])
    }
}



슬라이스 자르기 (Slicing slices)

슬라이스는 재분할 할 수도 있고, 같은 배열을 가리키는(point) 새로운 슬라이스를 만들 수 도 있습니다.

func main() {
    p := []int{2, 3, 5, 7, 11, 13}
    fmt.Println("p ==", p)
    fmt.Println("p[1:4] ==", p[1:4])

    // missing low index implies 0
    fmt.Println("p[:3] ==", p[:3])

    // missing high index implies len(s)
    fmt.Println("p[4:] ==", p[4:])
}
/* 
p == [2 3 5 7 11 13]
p[1:4] == [3 5 7]
p[:3] == [2 3 5]
p[4:] == [11 13]
*/



슬라이스 만들기

슬라이스는 make 함수로도 만들 수 있습니다.

첫번째 파라미터에 생성할 슬라이스 타입을 지정하고,

두번째는 Length(슬라이스의 길이), 그리고

세번째는 Capacity(내부 배열의 최대 길이)를 지정하면 모든 요소가 Zero value를 갖는다.

여기서 만약 세번째 Capacity 파라미터를 생략하면 Length와 같은 값을 갖는다.

슬라이스의 길이 및 용량은 len(), cap()를 사용하여 확인할 수 있다.

func main() {
    var z []int // 빈 슬라이스 z == nil
    a := make([]int, 5)
    printSlice("a", a)
    b := make([]int, 0, 5)
    printSlice("b", b)
    c := b[:2]
    printSlice("c", c)
    d := c[2:5]
    printSlice("d", d)
}

func printSlice(s string, x []int) {
    fmt.Printf("%s len=%d cap=%d %v\n",
        s, len(x), cap(x), x)
}
/*
a len=5 cap=5 [0 0 0 0 0]
b len=0 cap=5 []
c len=2 cap=5 [0 0]
d len=3 cap=3 [0 0 0]
*/



레인지 (Range, 범위)

for 반복문에서 range를 사용하면 슬라이스나 맵을 순회(iterates) 할 수 있습니다.

var pow = []int{1, 2, 4, 8, 16, 32, 64, 128}

func main() {
    for i, v := range pow {
        fmt.Printf("2**%d = %d\n", i, v)
    }
}



레인지 (2)

_ 를 이용해서 인덱스(index)나 값(value)를 무시할 수 있습니다.

index 만 필요하다면 value 부분을 제거하면 되고,

value만 필요하다면 index 부분을 _ 로 대체하면 됩니다.

  func main() {
    pow := make([]int, 10)
    for i := range pow {
        pow[i] = 1 << uint(i)
    }
    for _, value := range pow {
        fmt.Printf("%d\n", value)
    }
}
/*
1
2
4
8
...
512
*/



맵 (Maps)

맵은 값에 키를 지정합니다.

맵은 반드시 사용하기 전에 make 를 명시해야합니다. (주의: new 가 아닙니다)

make 를 수행하지 않은 nil 에는 값을 할당할 수 없습니다.

type Vertex struct {
    Lat, Long float64
    s string
}

var m map[string]Vertex

func main() {
    m = make(map[string]Vertex)
    m["Bell Labs"] = Vertex{
        40.68433, -74.39967, "test",
    }
    m["Bell Labss"] = Vertex{
        40.68433, -74.39967, "abc",
    }
    
    fmt.Println(m["Bell Labss"])
}
// {40.68433 -74.39967 abc}



맵 리터럴 (Map literals)

맵 리터럴은 구조체 리터럴과 비슷하지만 key 를 반드시 지정해야 합니다.

type Vertex struct {
    Lat, Long float64
}

var m = map[string]Vertex{
    "Bell Labs": Vertex{
        40.68433, -74.39967,
    },
    "Google": Vertex{
        37.42202, -122.08408,
    },
}

func main() {
    fmt.Println(m)
    fmt.Println(m["Google"])
}
/*
map[Bell Labs:{40.68433 -74.39967} Google:{37.42202 -122.08408}]
{37.42202 -122.08408}
*/



맵 리터럴 (2)

만약 가장 상위의 타입이 타입명이라면 리터럴에서 타입명을 생략해도 됩니다.

"Bell Labs": {40.68433, -74.39967}

또는

"Bell Labs": Vertex{40.68433, -74.39967}

는 같은 표현입니다.

type Vertex struct {
    Lat, Long float64
}

var m = map[string]Vertex{
    "Bell Labs": {40.68433, -74.39967},
    "Google":    {37.42202, -122.08408},
}

func main() {
    fmt.Println(m)
}
// map[Bell Labs:{40.68433 -74.39967} Google:{37.42202 -122.08408}]



맵 다루기 (Mutating Maps)

func main() {
    m := make(map[string]int) // map을 사용하기전 반드시 make를 명시해야함
    						  // key: String, value: Int
    m["Answer"] = 42
    fmt.Println("The value:", m["Answer"])

    m["Answer"] = 48
    fmt.Println("The value:", m["Answer"])

    delete(m, "Answer")
    fmt.Println("The value:", m["Answer"])

    v, ok := m["Answer"]
    fmt.Println("The value:", v, "Present?", ok)
    // 위의  ok 의 값은 m 에 key 가 존재한다면 true 존재하지 않으면 false , elem 은 타입에 따라 0(zero value) 가 됩니다.
}
/*
The value: 42
The value: 48
The value: 0
The value: 0 Present? false
*/