소개
데이터 타입은 프로그램을 작성할 때 특정 변수가 저장할 값의 종류를 지정합니다. 데이터 타입은 또한 데이터에 수행할 수 있는 작업을 결정합니다.
이 글에서는 Go에 내장된 중요한 데이터 타입에 대해 살펴보겠습니다. 이는 데이터 타입의 완전한 조사는 아니지만, Go에서 사용할 수 있는 옵션에 대해 익숙해지는 데 도움이 될 것입니다. 몇 가지 기본 데이터 타입을 이해하면 효율적으로 실행되는 더 명확한 코드를 작성할 수 있습니다.
배경
데이터 타입에 대해 생각해볼 수 있는 한 가지 방법은 현실 세계에서 사용하는 다양한 종류의 데이터를 고려하는 것입니다. 현실 세계의 데이터 예로는 숫자가 있습니다: 우리는 전체 숫자 (0, 1, 2, …), 정수 (…, -1, 0, 1, …), 그리고 무리수 (π) 등을 사용할 수 있습니다.
보통, 수학에서는 다른 종류의 숫자를 결합하여 어떤 종류의 답을 얻을 수 있습니다. 예를 들어, 5를 π에 더하고 싶을 수 있습니다:
5 + π
무리수를 고려하여 답으로 방정식을 유지하거나, π를 소수점 이하 자릿수가 줄어든 숫자로 반올림한 다음 숫자를 더할 수 있습니다:
5 + π = 5 + 3.14 = 8.14
하지만, 만약 우리가 숫자를 다른 데이터 타입, 예를 들어 단어와 같은 것으로 평가하려고 시도한다면, 일이 덜 이치에 맞게 되기 시작합니다. 다음 방정식을 어떻게 풀 수 있을까요?
shark + 8
컴퓨터의 경우, 각 데이터 타입은 매우 다릅니다—단어와 숫자처럼요. 결과적으로 우리는 값을 할당하고 연산을 통해 조작하는 방식에 있어 다양한 데이터 타입을 사용하는 것에 주의해야 합니다.
정수
수학에서와 같이, 컴퓨터 프로그래밍에서 정수는 양수, 음수 또는 0인 정수입니다 (…, -1, 0, 1, …). Go에서 정수는 int
로 알려져 있습니다. 다른 프로그래밍 언어와 마찬가지로, 4자리 이상의 숫자에는 쉼표를 사용하지 않아야 하므로 프로그램에서 1,000을 작성할 때는 1000
으로 작성하세요.
다음과 같이 간단한 방법으로 정수를 출력할 수 있습니다:
Output-459
또는, 이 경우 우리가 사용하거나 조작하는 숫자의 기호인 변수를 선언할 수 있습니다:
Output-459
Go에서 정수로 수학 연산을 할 수도 있습니다. 다음 코드 블록에서, 우리는 :=
할당 연산자를 사용하여 변수 sum
을 선언하고 인스턴스화할 것입니다:
Output48
출력에서 보듯이, 수학 연산자 -
는 정수 68
을 116
에서 뺐으며, 그 결과 48
이 되었습니다. 변수 선언에 대해 더 자세히 알아보려면 변수에 대한 데이터 타입 선언 섹션을 참조하세요.
정수는 Go 프로그램 내에서 다양한 방식으로 사용될 수 있습니다. Go에 대해 계속 배우면서 정수를 다루고 이 데이터 타입에 대한 지식을 확장할 수 있는 많은 기회를 가질 것입니다.
부동 소수점 숫자
부동 소수점 숫자 또는 float는 정수로 표현할 수 없는 실수를 나타내는 데 사용됩니다. 실수는 모든 유리수와 무리수를 포함하므로, 부동 소수점 숫자는 9.0 또는 -116.42와 같은 소수 부분을 포함할 수 있습니다. Go 프로그램에서 float를 생각할 때, 이는 소수점을 포함하는 숫자입니다.
정수와 마찬가지로, 부동 소수점 숫자를 간단한 방식으로 출력할 수 있습니다:
Output-459.67
또한 다음과 같이 float를 대표하는 변수를 선언할 수도 있습니다:
Output-459.67
정수와 마찬가지로, Go에서도 float로 수학 연산을 할 수 있습니다:
Output929.24
정수와 부동 소수점 숫자를 다룰 때, 3과 3.0은 다르다는 점을 유의해야 합니다. 3은 정수를 나타내고 3.0은 float를 나타냅니다.
숫자 타입의 크기
Go 언어는 정수와 부동 소수점 이외에도, 정적이거나 동적인 크기 특성에 따라 구분되는 두 가지 숫자 데이터 형식을 가지고 있습니다. 첫 번째 형식은 아키텍처 독립적인 형식으로, 비트 단위의 데이터 크기는 코드가 실행되는 기계와 관계없이 변하지 않습니다.
현재 대부분의 시스템 아키텍처는 32비트 또는 64비트입니다. 예를 들어, 현대 윈도우 노트북에 대해 개발하는 경우, 운영 체제가 64비트 아키텍처에서 실행될 수 있습니다. 그러나 피트니스 와치 같은 장치에 대해 개발하는 경우, 32비트 아키텍처로 작업할 수 있습니다. int32
같은 아키텍처 독립적인 형식을 사용하면, 컴파일 대상 아키텍처와 관계없이 형식의 크기는 일정하게 유지됩니다.
두 번째 형식은 구현 특정적인 형식입니다. 이 형식에서는 비트 크기가 프로그램이 빌드되는 아키텍처에 따라 달라질 수 있습니다. 예를 들어, int
형식을 사용하면, Go가 32비트 아키텍처로 컴파일될 때, 데이터 형식의 크기는 32비트가 됩니다. 프로그램이 64비트 아키텍처로 컴파일될 경우, 변수의 크기는 64비트가 됩니다.
데이터 형식의 크기가 다를 뿐만 아니라, 정수형은 두 가지 기본 형식으로 나뉘어집니다: 부호 있는와 부호 없는. int8
는 부호 있는 정수로, -128에서 127까지의 값이 될 수 있습니다. uint8
는 부호 없는 정수로, 0에서 255까지의 양수 값만 가질 수 있습니다.
이것은 기본적으로 바이트 크기에 따라 설정되는 범위입니다. 8位의 的二进制 데이터는 总共 256 种不同的值를 지원합니다. 이유는 8 位整型(int8) 数据需要同时支持正负值, 因此其范围为-128 到 127, 共256个唯一的值。
Go 使用以下与架构无关的整数类型:
uint8 unsigned 8-bit integers (0 to 255)
uint16 unsigned 16-bit integers (0 to 65535)
uint32 unsigned 32-bit integers (0 to 4294967295)
uint64 unsigned 64-bit integers (0 to 18446744073709551615)
int8 signed 8-bit integers (-128 to 127)
int16 signed 16-bit integers (-32768 to 32767)
int32 signed 32-bit integers (-2147483648 to 2147483647)
int64 signed 64-bit integers (-9223372036854775808 to 9223372036854775807)
浮点和复数也有各种大小:
float32 IEEE-754 32-bit floating-point numbers
float64 IEEE-754 64-bit floating-point numbers
complex64 complex numbers with float32 real and imaginary parts
complex128 complex numbers with float64 real and imaginary parts
还有几个别名数字类型,它们为特定的数据类型分配了有用的名称:
byte alias for uint8
rune alias for int32
byte 别名的目的是为了在程序中清晰地表示字符串元素中的字节数据测量, 而不是与字节数据测量无关的小整数。即使编译后 byte
和 uint8
是相同的, 在程序中 byte
通常用于表示字符数据的数值形式, 而 uint8
则用于表示程序中的数字。
此外, Go 还提供了以下实现特定类型的:
runes 也不同。其中 byte
和 uint8
完全相同, 但 rune 可以是一个字节或四个字节, 由 int32
决定。一个 rune 用于表示 Unicode 字符, 而不是仅由 int32
表示的 ASCII 字符。
uint unsigned, either 32 or 64 bits
int signed, either 32 or 64 bits
uintptr unsigned integer large enough to store the uninterpreted bits of a pointer value
另外, Go 还提供了以下实现特定类型的:
숫자 데이터 유형 선택
올바른 크기를 선택하는 것은 일반적으로 작업 중인 데이터의 크기보다 프로그래밍하는 대상 아키텍처의 성능과 더 관련이 있습니다. 그러나 프로그램의 성능에 대한 구체적인 영향을 알 필요 없이 처음 시작할 때 이러한 기본 지침을 따를 수 있습니다.
이 기사의 앞부분에서 논의한 바와 같이, 아키텍처에 독립적인 유형과 구현에 특정한 유형이 있습니다. 정수 데이터의 경우, Go에서는 int64
나 uint64
대신 int
나 uint
와 같은 구현 유형을 사용하는 것이 일반적입니다. 이렇게 하면 일반적으로 대상 아키텍처에서 가장 빠른 처리 속도를 얻을 수 있습니다. 예를 들어, int64
를 사용하고 32비트 아키텍처로 컴파일하면 아키텍처를 가로질러 데이터를 이동하는 데 추가 CPU 사이클이 필요하므로 이러한 값을 처리하는 데 적어도 두 배의 시간이 걸립니다. 대신 int
를 사용했다면, 프로그램은 32비트 아키텍처에 대해 32비트 크기로 정의되었을 것이며, 처리 속도가 훨씬 빨랐을 것입니다.
특정 크기 범위를 초과하지 않을 것이라는 것을 알고 있다면, 아키텍처에 독립적인 유형을 선택하여 속도를 높이고 메모리 사용량을 줄일 수 있습니다. 예를 들어, 데이터가 100
을 초과하지 않고 양수만 될 것이라는 것을 알고 있다면, uint8
를 선택하면 메모리를 덜 사용하여 프로그램을 더 효율적으로 만들 수 있습니다.
이제 숫자 데이터 타입의 가능한 범위 중 일부를 살펴보았으니, 프로그램에서 이러한 범위를 초과할 경우 어떤 일이 발생하는지 살펴보겠습니다.
오버플로우 vs. 랩어라운드
Go는 값이 컴파일 타임에 계산되는지 런타임에 계산되는지에 따라 숫자를 오버플로우하거나 랩어라운드할 수 있습니다. 컴파일 타임 에러는 프로그램이 빌드를 시도할 때 에러를 발견하면 발생하고, 런타임 에러는 프로그램이 컴파일된 후 실행 중에 발생합니다.
다음 예제에서는 maxUint32
를 최대값으로 설정합니다:
이 코드는 컴파일되고 다음과 같은 결과를 실행합니다:
런타임에 1
을 값에 더하면 0
으로 랩어라운드됩니다:
한편, 컴파일 타임 이전에 변수에 1
을 더하도록 프로그램을 변경해 보겠습니다:
컴파일 타임에 컴파일러가 지정된 데이터 타입에 값이 너무 크다고 판단하면 overflow
에러를 발생시킵니다. 이는 계산된 값이 지정한 데이터 타입에 비해 너무 크다는 것을 의미합니다.
컴파일러가 값이 오버플로우될 것을 판단하면 이제 에러를 발생시킵니다:
Outputprog.go:6:36: constant 4294967296 overflows uint32
데이터의 경계를 이해하면 향후 프로그램에서 잠재적인 버그를 피할 수 있습니다.
이제 숫자 유형에 대해 다루었으니, 부울 값을 저장하는 방법을 살펴보겠습니다.
부울
부울 데이터 유형은 true
또는 false
두 가지 값 중 하나일 수 있으며, 데이터 유형으로 선언할 때 bool
로 정의됩니다. 부울은 컴퓨터 과학의 알고리즘에 영향을 미치는 수학의 논리 분야와 관련된 진실 값을 나타내는 데 사용됩니다.
true
와 false
값은 모두 소문자 t
와 f
로 표시되며, Go에서 미리 선언된 식별자이기 때문입니다.
수학의 많은 연산은 결과가 참 또는 거짓으로 평가됩니다:
- 크다
- 500 > 100 true
- 1 > 5 false
- 작다
- 200 < 400 true
- 4 < 2 false
- 같다
- 5 = 5 true
- 500 = 400 false
숫자와 마찬가지로 변수에 부울 값을 저장할 수 있습니다:
그런 다음 fmt.Println()
함수를 호출하여 부울 값을 출력할 수 있습니다:
5
는 8
보다 크지 않기 때문에 다음과 같은 출력을 받게 됩니다:
Outputfalse
Go에서 더 많은 프로그램을 작성하면서 부울이 어떻게 작동하는지, 그리고 다양한 함수와 연산이 true
또는 false
로 평가되어 프로그램의 흐름을 어떻게 바꿀 수 있는지 더 잘 이해하게 될 것입니다.
문자열
문자열은 하나 이상의 문자(문자, 숫자, 기호) 시퀀스로, 상수 또는 변수일 수 있습니다. 문자열은 Go에서 백틱 `
또는 큰따옴표 "
안에 존재하며, 사용하는 따옴표에 따라 다른 특성을 가집니다.
백틱을 사용하면 원시 문자열 리터럴을 만들고, 큰따옴표를 사용하면 해석된 문자열 리터럴을 만듭니다.
원시 문자열 리터럴
원시 문자열 리터럴은 백틱 사이의 문자 시퀀스로, 종종 백틱이라고 불립니다. 따옴표 안에서는 백틱 문자 자체를 제외한 모든 문자가 백틱 사이에 표시되는 대로 나타납니다.
OutputSay "hello" to Go!
보통, 백슬래시는 문자열에서 특수 문자를 나타내는 데 사용됩니다. 예를 들어, 해석된 문자열에서 \n
은 문자열의 새 줄을 나타냅니다. 하지만 백슬래시는 원시 문자열 리터럴 내에서는 특별한 의미를 갖지 않습니다:
원시 문자열 리터럴에서 백슬래시는 특별한 의미가 없으므로, 실제로 \n
의 값을 출력하게 되어 새 줄을 만들지 않습니다:
OutputSay "hello" to Go!\n
원시 문자열 리터럴은 여러 줄의 문자열을 만드는 데에도 사용될 수 있습니다:
OutputThis string is on
multiple lines
within a single back
quote on either side.
앞의 코드 블록에서 새 줄들은 입력에서 출력으로 그대로 전달되었습니다.
해석된 문자열 리터럴
해석된 문자열 리터럴은 "bar"
와 같이 큰따옴표 사이의 문자 시퀀스입니다. 큰따옴표 안에서는 새 줄과 이스케이프 처리되지 않은 큰따옴표를 제외한 모든 문자가 나타날 수 있습니다. 해석된 문자열에서 큰따옴표를 표시하려면, 다음과 같이 백슬래시를 이스케이프 문자로 사용할 수 있습니다:
OutputSay "hello" to Go!
해석된 문자열 리터럴을 거의 항상 사용하게 될 것입니다. 왜냐하면 그 안에서 이스케이프 문자를 사용할 수 있기 때문입니다. 문자열 작업에 대한 더 자세한 내용은 Go에서 문자열 작업 소개를 확인하세요.
UTF-8 문자가 포함된 문자열
UTF-8은 문자를 1바이트에서 4바이트까지 가변 폭으로 인코딩하는 데 사용되는 인코딩 방식입니다. Go는 특별한 설정, 라이브러리 또는 패키지 없이 기본적으로 UTF-8 문자를 지원합니다. 문자 A
와 같은 로마 문자는 숫자 65와 같은 ASCII 값으로 표현될 수 있습니다. 그러나 世
와 같은 특수 문자의 경우 UTF-8이 필요합니다. Go는 UTF-8 데이터에 rune
별칭 타입을 사용합니다.
Go에서 for
루프와 range
키워드를 사용하여 모든 문자열, 심지어 UTF-8 문자열을 인덱싱할 수 있습니다. for
루프와 range
는 이 시리즈의 뒷부분에서 더 자세히 다룰 것입니다. 지금은 이를 사용하여 주어진 문자열의 바이트를 계산할 수 있다는 것을 아는 것이 중요합니다:
위의 코드 블록에서 변수 a
를 선언하고 그 값에 Hello, 世界
를 할당했습니다. 할당된 텍스트에는 UTF-8 문자가 포함되어 있습니다.
그런 다음 표준 for
루프와 range
키워드를 사용했습니다. Go에서 range
키워드는 문자열을 인덱싱하여 한 번에 하나의 문자와 해당 문자가 있는 바이트 인덱스를 반환합니다.
fmt.Printf
함수를 사용하여 %d: %s\n
형식 문자열을 제공했습니다. %d
는 숫자(이 경우 정수)를 위한 인쇄 동사이며, %s
는 문자열을 위한 인쇄 동사입니다. 그런 다음 for
루프의 현재 인덱스인 i
와 for
루프의 현재 문자인 c
의 값을 제공했습니다.
마지막으로 내장 len
함수를 사용하여 변수 a
의 전체 길이를 출력했습니다.
이전에 룬이 int32
의 별칭이며 1에서 4바이트로 구성될 수 있다고 언급했습니다. 世
문자는 정의하는 데 3바이트가 필요하며 UTF-8 문자열을 순회할 때 인덱스가 그에 따라 이동합니다. 이것이 i
가 출력될 때 순차적이지 않은 이유입니다.
Output0: H
1: e
2: l
3: l
4: o
5: ,
6:
7: 世
10: 界
length of 'Hello, 世界': 13
보시다시피, 길이는 문자열을 순회하는 횟수보다 길습니다.
항상 UTF-8 문자열로 작업하는 것은 아니지만, 그럴 때는 이제 그들이 룬이고 단일 int32
가 아닌 이유를 이해할 것입니다.
변수에 대한 데이터 타입 선언
이제 다양한 기본 데이터 타입에 대해 알았으니, Go에서 이러한 타입을 변수에 할당하는 방법을 살펴보겠습니다.
Go에서는 var
키워드 다음에 변수 이름과 원하는 데이터 타입을 사용하여 변수를 정의할 수 있습니다.
다음 예제에서는 float64
타입의 pi
라는 변수를 선언할 것입니다.
키워드 var
가 먼저 선언됩니다:
그 다음에 우리의 변수 이름인 pi
가 따라옵니다:
마지막으로 데이터 타입인 float64
가 선언됩니다:
선택적으로 초기 값을 지정할 수도 있습니다. 예를 들어 3.14
:
Go는 정적 타입 언어입니다. 정적 타입이란 프로그램의 각 문장이 컴파일 시간에 검사된다는 것을 의미합니다. 또한 데이터 타입이 변수에 연결되는 반면, 동적 타입 언어에서는 데이터 타입이 값에 연결됩니다.
예를 들어, Go에서는 변수를 선언할 때 타입이 선언됩니다:
이러한 각 변수는 선언 방식에 따라 다른 데이터 타입이 될 수 있습니다.
이는 데이터 타입이 값과 연결되는 PHP와 같은 언어와는 다릅니다:
앞의 코드 블록에서 첫 번째 $s
는 값 "sammy"
가 할당되었기 때문에 문자열이고, 두 번째는 값이 123
이기 때문에 정수입니다.
다음으로, 배열과 같은 더 복잡한 데이터 타입을 살펴보겠습니다.
배열
배열은 요소들의 순서화된 시퀀스입니다. 배열의 용량은 생성 시점에 정의됩니다. 배열이 크기를 할당하면 그 크기는 더 이상 변경할 수 없습니다. 배열의 크기가 정적이기 때문에 메모리를 한 번만 할당한다는 것을 의미합니다. 이로 인해 배열은 다루기에 다소 뻣뻣하지만 프로그램의 성능을 향상시킵니다. 이러한 이유로 배열은 일반적으로 프로그램을 최적화할 때 사용됩니다. 슬라이스는 다음에 다룰 예정이며, 다른 언어에서 배열이라고 생각하는 것보다 훨씬 유연합니다.
배열은 배열의 크기를 선언한 다음 중괄호 { }
사이에 정의된 값과 함께 데이터 타입을 선언하여 정의됩니다.
문자열 배열은 다음과 같습니다:
배열을 변수에 저장하고 출력할 수 있습니다:
Output[blue coral staghorn coral pillar coral]
앞서 언급했듯이, 슬라이스는 배열과 유사하지만 훨씬 더 유연합니다. 이 가변 데이터 타입을 살펴보겠습니다.
슬라이스
슬라이스는 길이가 변할 수 있는 요소들의 순서화된 시퀀스입니다. 슬라이스는 동적으로 크기를 늘릴 수 있습니다. 슬라이스에 새 항목을 추가할 때 슬라이스에 새 항목을 저장할 충분한 메모리가 없으면 필요에 따라 시스템에서 더 많은 메모리를 요청합니다. 슬라이스는 필요할 때 더 많은 요소를 추가하여 확장할 수 있기 때문에 배열보다 더 자주 사용됩니다.
슬라이스는 여는 대괄호 []
와 닫는 대괄호 []
앞에 데이터 타입을 선언하고 중괄호 {}
사이에 값을 넣어 정의합니다.
정수 슬라이스는 다음과 같습니다:
실수 슬라이스는 다음과 같습니다:
문자열 슬라이스는 다음과 같습니다:
seaCreatures
라는 문자열 슬라이스를 정의해봅시다:
변수를 호출하여 출력할 수 있습니다:
출력은 우리가 생성한 목록과 정확히 같게 나타납니다:
Output[shark cuttlefish squid mantis shrimp]
append
키워드를 사용하여 슬라이스에 항목을 추가할 수 있습니다. 다음 명령은 슬라이스에 seahorse
라는 문자열 값을 추가합니다:
출력하여 추가되었는지 확인할 수 있습니다:
Output[shark cuttlefish squid mantis shrimp seahorse]
알 수 없는 크기의 요소를 관리해야 할 경우, 슬라이스는 배열보다 훨씬 다양한 용도로 사용될 수 있습니다.
맵
맵은 Go의 내장 해시 또는 딕셔너리 타입입니다. 맵은 키와 값을 쌍으로 사용하여 데이터를 저장합니다. 이는 프로그래밍에서 인덱스 또는 키를 통해 값을 빠르게 조회하는 데 유용합니다. 예를 들어, 사용자 ID로 인덱싱된 사용자 맵을 유지하고 싶을 수 있습니다. 키는 사용자 ID가 되고, 사용자 객체는 값이 됩니다. 맵은 map
키워드를 사용하여 생성하며, 뒤에 키 데이터 타입을 대괄호 []
안에 넣고, 값 데이터 타입과 중괄호 안에 키-값 쌍을 넣습니다.
map[key]value{}
일반적으로 관련된 데이터를 보관하는 데 사용되며, 예를 들어 ID에 포함된 정보와 같은 데이터를 보관하는 맵은 다음과 같습니다:
중괄호 외에도 맵 전체에 콜론이 있음을 알 수 있습니다. 콜론 왼쪽의 단어는 키입니다. 키는 Go에서 비교 가능한 모든 비교 가능한 유형일 수 있습니다. 비교 가능한 유형은 문자열
, 정수
등과 같은 기본 유형입니다. 기본 유형은 언어에 의해 정의되며 다른 유형을 결합하여 구축되지 않습니다. 사용자 정의 유형일 수도 있지만, 프로그래밍 오류를 피하기 위해 간단하게 유지하는 것이 가장 좋습니다. 위의 사전에서 키는 이름
, 동물
, 색상
, 위치
입니다.
콜론 오른쪽의 단어는 값입니다. 값은 모든 데이터 유형으로 구성될 수 있습니다. 위의 사전에서 값은 새미
, 상어
, 파란색
, 바다
입니다.
맵을 변수에 저장하고 출력해 보겠습니다:
Outputmap[animal:shark color:blue location:ocean name:Sammy]
새미의 색상을 분리하려면 새미["색상"]
을 호출하면 됩니다. 이를 출력해 보겠습니다:
Outputblue
맵은 데이터를 저장하기 위한 키-값 쌍을 제공하므로 Go 프로그램에서 중요한 요소가 될 수 있습니다.
결론
이 시점에서, Go에서 사용할 수 있는 몇 가지 주요 데이터 타입에 대해 더 잘 이해하고 있어야 합니다. 이러한 각 데이터 타입은 Go 언어로 프로그래밍 프로젝트를 개발할 때 중요해질 것입니다.
Go에서 사용 가능한 데이터 타입을 확실히 이해하고 나면, 상황에 따라 데이터 타입을 변경하기 위해 데이터 타입을 변환하는 방법을 배울 수 있습니다.
Source:
https://www.digitalocean.com/community/tutorials/understanding-data-types-in-go