1. Go 언어 데이터 타입 소개

Go 언어에서 데이터 타입은 프로그래밍의 기초로, 변수가 저장할 수 있는 데이터의 형식을 결정합니다. Go 언어에서 제공하는 기본 데이터 타입은 주로 다음과 같은 범주로 나뉘어집니다:

데이터 타입 설명 메모리 사용량
bool 참 또는 거짓을 저장하는 부울(boolean) 타입 1바이트
int, uint 부호 있는 정수와 부호 없는 정수, 기본 크기는 시스템 플랫폼에 따라 다름 4 또는 8바이트
int8, uint8 8비트 부호 있는 정수와 부호 없는 정수 1바이트
int16, uint16 16비트 부호 있는 정수와 부호 없는 정수 2바이트
int32, uint32 32비트 부호 있는 정수와 부호 없는 정수 4바이트
int64, uint64 64비트 부호 있는 정수와 부호 없는 정수 8바이트
float32 32비트 부동 소수점 숫자 4바이트
float64 64비트 부동 소수점 숫자 8바이트
complex64 32비트 실수부와 허수부를 가지는 복소수 8바이트
complex128 64비트 실수부와 허수부를 가지는 복소수 16바이트
byte uint8과 유사 1바이트
rune int32와 유사하며, 유니코드 코드 포인트를 나타냄 4바이트
string 문자열 타입 문자열 길이에 따라 다름
error 오류 정보를 반환하는 데 사용되는 오류 인터페이스 고정된 크기 없음

이러한 데이터 타입은 숫자 계산, 텍스트 처리 또는 논리적 제어 등 다양한 요구에 따라 선택할 수 있습니다.

2. 정수형 데이터 타입

2.1 정수형 타입 개요

Go 언어에는 여러 내장 정수형 타입이 있으며, 다음과 같이 분류됩니다:

  • 부호 있는 정수: int8, int16, int32 (또는 rune), int64, int
  • 부호 없는 정수: uint8 (또는 byte), uint16, uint32, uint64, uint

intuint의 크기는 32비트 시스템에서는 4바이트이고, 64비트 시스템에서는 8바이트입니다. 정수 데이터 타입의 값 범위는 아래 표에 나와 있습니다:

타입 값 범위
int8 -128부터 127까지
uint8 0부터 255까지
int16 -32768부터 32767까지
uint16 0부터 65535까지
int32 -2147483648부터 2147483647까지
uint32 0부터 4294967295까지
int64 -9223372036854775808부터 9223372036854775807까지
uint64 0부터 18446744073709551615까지

2.2 정수 변수 사용하기

정수 변수를 선언하는 기본 구문은 아래와 같습니다:

var 변수_이름 데이터_타입 = 초기_값

예시 코드:

package main
import "fmt"

func main() {
    var a int = 10 // 부호 있는 정수 변수
    var b uint = 20 // 부호 없는 정수 변수
    var c int8 = -128 // 가장 작은 int8 값
    fmt.Println(a, b, c)
}

2.3 정수 연산

Go 언어는 덧셈 (+), 뺄셈 (-), 곱셈 (*), 나눗셈 (/), 나머지 (%) 등의 일반 산술 연산자를 지원하며, 비트 연산자인 비트 AND (&), OR (|), XOR (^), 좌측 시프트 (<<), 우측 시프트 (>>)도 지원합니다.

package main
import "fmt"

func main() {
    x := 10
    y := 3

    // 산술 연산
    fmt.Println(x + y) // 덧셈
    fmt.Println(x - y) // 뺄셈
    fmt.Println(x * y) // 곱셈
    fmt.Println(x / y) // 나눗셈
    fmt.Println(x % y) // 나머지

    // 비트 연산
    fmt.Println(x & y)  // 비트 AND
    fmt.Println(x | y)  // 비트 OR
    fmt.Println(x ^ y)  // 비트 XOR
    fmt.Println(x << 1) // 좌측 시프트 1회
    fmt.Println(x >> 1) // 우측 시프트 1회
}

3. 부동 소수점 데이터 타입

3.1 부동 소수점 데이터 유형 개요

Go 언어에서는 부동 소수점 유형으로 float32float64가 있으며, 각각 32비트와 64비트 부동 소수점 데이터에 해당합니다. 일반적으로 더 큰 범위와 더 정확한 정밀도를 제공하는 float64를 사용하는 것이 권장됩니다.

  • float32는 약 23개의 유효 비트를 가지며, 약 7자리의 십진수 정밀도를 제공합니다.
  • float64는 약 52개의 유효 비트를 가지며, 약 16자리의 십진수 정밀도를 제공합니다.

3.2 부동 소수점 변수 사용하기

부동 소수점 변수는 리터럴을 직접 제공하거나 var 키워드를 사용하여 선언할 수 있습니다.

package main
import "fmt"

func main() {
    var f1 float32 = 3.14 // 명시적으로 float32 유형 지정
    f2 := 3.14            // float64 유형으로 자동 추론
    fmt.Println(f1, f2)
}

3.3 부동 소수점 산술 및 이슈

부동 소수점 산술은 정밀도 손실을 유발할 수 있습니다. 특히 두 매우 가까운 숫자를 빼는 경우와 같이 매우 높은 정밀도로 작업하는 것은 일반적인 문제입니다.

package main
import "fmt"

func main() {
    f1 := .1
    f2 := .2
    f3 := f1 + f2
    fmt.Println(f3) // 정밀도 문제로 예상한 .3이 출력되지 않을 수 있음

    // 형식화된 출력을 사용하여 정밀도 문제 해결
    fmt.Printf("%.1f\n", f3) // 출력이 .3으로 수정됨
}

4 부울 데이터 유형

4.1 부울 데이터 유형 개요

부울은 가장 간단한 데이터 유형으로, true (참)와 false (거짓) 두 가지 값만 가질 수 있습니다. 조건문과 루프 제어 구조에서 매우 중요한 역할을 합니다.

4.2 부울 변수 사용하기

부울 변수를 선언하고 사용하는 방법:

package main
import "fmt"

func main() {
    var success bool = true
    var fail bool = false
    fmt.Println("작업 성공:", success)
    fmt.Println("작업 실패:", fail)
}

부울 값은 종종 조건문에서 사용됩니다:

package main
import "fmt"

func main() {
    a := 10
    b := 20
    fmt.Println("a == b:", a == b) // false
    fmt.Println("a < b:", a < b)   // true
}

5 문자열 데이터 유형

5.1 문자열 개요

문자열은 문자의 모음입니다. Go 언어에서 문자열은 변경할 수 없습니다. 각 문자열은 기본 바이트 배열의 포인터와 길이로 구성됩니다. 문자열은 바이트를 포함한 모든 데이터를 담을 수 있습니다.

5.2 문자열 변수 사용하기

문자열 변수는 일반적으로 이중 인용부호 "를 사용하여 만들지만, 여러 줄의 문자열을 만들기 위해 백틱 `을 사용할 수도 있습니다:

package main
import "fmt"

func main() {
    var s1 string = "hello"
    s2 := "world"
    s3 := `여러 줄로
    구성된 
    문자열`
    fmt.Println(s1)
    fmt.Println(s2)
    fmt.Println(s3)
}

문자열이 생성되면 그 내용을 변경할 수 없습니다. 다음 작업은 부적절하며 컴파일 오류를 유발합니다:

s := "hello"
s[] = 'H` // 컴파일 오류: 문자열 내용은 변경할 수 없음

5.3 문자열 작업

문자열은 프로그래밍에서 매우 일반적이고 중요합니다. Go 언어는 문자열 조작을 위한 다양한 내장 함수를 제공합니다. 일반적으로 사용되는 몇 가지 작업은 다음과 같습니다.

5.3.1 문자열 연결

Go 언어에서 문자열을 연결하기 위해 더하기 기호 (+) 연산자를 사용할 수 있으며, 성능을 위해 여러 문자열을 빈번하게 연결해야 하는 경우에는 strings.Builder를 사용하는 것이 좋습니다.

package main

import (
    "fmt"
    "strings"
)

func main() {
    // +를 사용하여 문자열 연결
    hello := "안녕, "
    world := "세상!"
    result := hello + world
    fmt.Println(result) // 출력: 안녕, 세상!

    // strings.Builder를 사용하여 문자열 연결
    var sb strings.Builder
    sb.WriteString("안녕, ")
    sb.WriteString("세상!")
    fmt.Println(sb.String()) // 출력: 안녕, 세상!
}

5.3.2 문자열 분할

문자열을 지정된 구분자를 기반으로 슬라이스로 분할하는 작업은 strings.Split 함수를 사용하여 수행할 수 있습니다.

package main

import (
    "fmt"
    "strings"
)

func main() {
    // 문자열 정의
    sentence := "Go는 오픈 소스 프로그래밍 언어입니다"

    // 공백을 기준으로 문자열 분할
    words := strings.Split(sentence, " ")
    for _, word := range words {
        fmt.Printf("%s\n", word)
    }
    // 결과:
    // Go는
    // 오픈
    // 소스
    // 프로그래밍
    // 언어입니다
}

5.3.3 인덱스 접근

Go 언어에서 문자열은 변경할 수 없는 바이트 시퀀스입니다. 특정 바이트에 접근하기 위해 인덱싱을 사용할 수 있습니다. 그러나 UTF-8로 인코딩된 문자와 같은 다중바이트 문자가 포함된 문자열의 경우, 직접적인 인덱싱은 예상한 단일 문자를 얻을 수 없음에 유의해야 합니다.

package main

import "fmt"

func main() {
    s := "Hello, 世界"
    for i := 0; i < len(s); i++ {
        fmt.Printf("%d: %x\n", i, s[i])
    }
    // 참고: 이는 문자가 아닌 바이트의 16진수 표현을 출력합니다
}

문자 단위로 문자열을 반복하려면 range 루프를 사용할 수 있습니다.

package main

import "fmt"

func main() {
    s := "Hello, 世界"
    for index, runeValue := range s {
        fmt.Printf("%d: %U '%c'\n", index, runeValue, runeValue)
    }
    // 출력: 각 문자에 대한 인덱스, 유니코드 인코딩, 그리고 해당 문자
}

5.3.4 길이 가져오기

len 함수는 문자열의 길이, 즉 기본 바이트 시퀀스의 길이를 얻을 수 있습니다. UTF-8 문자열의 경우, 문자(룬)의 수를 얻으려면 utf8.RuneCountInString 함수를 사용해야 합니다. 이 함수는 다중바이트 문자를 올바르게 처리할 수 있습니다.

package main

import (
    "fmt"
    "unicode/utf8"
)

func main() {
    s := "Hello, 世界"
    fmt.Println("바이트 길이:", len(s)) // 바이트 길이 출력
    fmt.Println("문자 길이:", utf8.RuneCountInString(s)) // 문자 길이 출력
}

위의 예에서 보듯이 Go 언어는 다양한 문자열 처리 작업을 쉽게 수행할 수 있도록 풍부한 라이브러리 함수를 제공합니다. 코딩할 때, 특히 비 ASCII 문자 세트를 다룰 때에는 바이트와 문자 사이의 구별에 주의해야 합니다.