Golang

Golang 입문기 - 문법 2

kahnco 2023. 10. 27. 02:24

서두

 저번 게시글에서는 주로 문자열 관련된 Golang의 특징을 알아보았다. 이번 시간에는 상수, 변수, 타입에 대해서 집중적으로 알아볼 계획이다.

 


상수 (Constants)

 

 Golang에서 사용하는 상수에는 Boolean (진리값), Rune(유니코드 코드 포인트를 식별하는 정수 값), Integer (정수), Floating-point (부동소수점), Imaginary (허수), String (문자열) 상수가 있다. 룬, 정수, 부동 소수점 및 허수 상수를 집합적으로 숫자 상수라고 한다.

 

 상수 값은 룬, 정수, 부동 소수점, 허수 또는 문자열 리터럴, 상수를 나타내는 식별자, 상수 표현식, 상수인 결과로의 변환 또는 일부 내장된 결과값으로 표시된다. 또한, 상수 인수에 적용되는 min 또는 max, 특정 값에 적용되는 unsafe.Sizeof, 일부 표현식에 적용되는 cap 또는 len, 복소수 상수에 적용되는 real 및 image, 숫자 상수에 적용되는 complex 등의 함수, boolean 진리값은 미리 선언된 상수 true 혹은 false로 표현된다. 미리 선언된 식별자 iota는 정수 상수를 나타낸다.

1. min / max는 특정 데이터 유형의 최소값과 최대값을 나타내는 상수의 이름으로 자주 사용된다. 예를 들면 다음과 같다.

const (
    MinValue = 0
    MaxValue = 100
)

2. unsafe.Sizeof는 Golang의 unsafe 패키지에서 제공하는 함수이다. 주어진 표현식 유형의 크기를 바이트 단위로 반환한다.
이는 저수준 프로그래밍에서 중요할 수 있는 변수의 메모리 크기를 결정할 수 있기 때문에 "unsafe" 라고 불린다.

import "unsafe"

func main() {
    var x int
    size := unsafe.Sizeof(x)
    fmt.Println("Size of x:", size) // Output: Size of x: 8 (on a 64-bit system)
}

3. len 은 slice, array 혹은 map에서의 key들의 개수를 리턴한다.

numbers := []int{1, 2, 3, 4, 5}
fmt.Println(len(numbers)) // Output: 5

4. cap 은 추가 메모리를 할당하지 않고 slice가 보유할 수 있는 최대 수인 slice의 용량을 반환한다.

numbers := make([]int, 5, 10) // Slice with length 5 and capacity 10
fmt.Println(cap(numbers)) // Output: 10

5. real / imag 는 복소수와 함께 사용되는 Go의 내장 함수이다. 이는 복소수의 실수부와 허수부를 각각 반환한다.

c := complex(3, 4) // 3 + 4i
fmt.Println(real(c)) // Output: 3
fmt.Println(imag(c)) // Output: 4

6. complex 는 복소수를 생성하는데 사용되는 Go의 내장 함수이다. 실수부와 허수부라는 두 개의 인수를 사용해서 복소수를 반환한다.

c := complex(3, 4) // 3 + 4i

7. iota는 증분 숫자의 정의를 단순화하기 위해 const 선언에 사용되는 Go의 사전 선언된 특수 식별자이다. 0부터 시작하여 이후의 const 선언마다 1씩 증가한다.

const (
    A = iota // 0
    B = iota // 1
    C = iota // 2
)

 

 일반적으로 복소수 상수는 상수 표현의 한 형태이다.

 

 숫자 상수는 임의 정밀도의 정확한 값을 나타내며 overflow 되지 않는다. 결과적으로 IEEE-754 음수 0, 무한대 혹은 NaN 값을 나타내는 상수는 없다.

컴퓨터에서 실수를 표현하는데 사용되는 IEEE 754 부동 소수점 표준에는 "음의 0" 이라는 개념이 존재한다.

IEEE 754 표준에서 부동 소수점 숫자는 부호 비트, 지수 및 분수(가수 또는 유효 숫자라고도 함)로 표시된다. 부호 비트는 숫자가 양수인지 음수인지를 결정한다.

일반적으로 사용하는 0의 경우 부호 비트가 0 (양수 표시)이고, 지수와 분수도 모두 0이다. 그러나 음수 0의 경우 부호 비트가 1 (음수 표시)이고 지수와 분수 모두 0이다.

따라서 +0과 -0은 모두 동일한 숫자값(0)을 가지지만 서로 다른 부호 비트로 표현된다. 이렇게 실수를 표현함으로써 가지는 장점은 다음과 같다.

1. 계산의 일관성 (Consistency in Computations): 특정 수학적 계산에서는 양의 0과 음의 0을 구별하면 일관성이 보장된다. 예를 들어, 미적분학 및 수치 분석에서 극한과 관련된 표현식은 양수 측에서 0에 접근하는 것과 음수 측에서 0에 접근하는 것을 구별해야 할 수도 있다. 양수 및 음수 0을 사용하면 이러한 계산이 더 정확해진다.

2. 부호 정보 보존 (Preserving Sign Information): 일부 계산에서는 결과가 0인 경우에도 부호 정보를 유지하는 것이 중요하다. 예를 들어, 방향이 중요한 물리량을 다루는 경우 +-0 을 모두 나타내는 방법을 사용하면 부호 정보가 손질되지 않는다.

그러나, 대부분의 실제 프로그래밍 상황에서 개발자는 +0과 -0의 차이에 대해 걱정할 필요가 없다. 대부분의 프로그래밍 언어와 응용 프로그램은 이를 동일하게 취급하며 0과 관련된 연산은 부호에 관계없이 동일하게 작동한다. 음수 0의 개념은 IEEE 754 표준의 뉘앙스에 가깝고 부호 정보를 0으로 유지하는 것이 필수적인 특수 수학 및 과학 계산과 주로 관련이 있다.

 

 상수는 타입이 지정되거나 지정되지 않을 수 있다. 리터럴 상수, true, false, iota 및 타입이 지정되지 않은 상수 피연산자만 포함하는 특정 상수 표현식은 타입이 지정되지 않는다.

 

 상수는 상수 선언이나 변환을 통해 명시적으로 타입이 지정될 수도 있고, 변수 선언이나 대입문에서 사용되거나 식의 피연산자로 사용될 때 암시적으로 타입이 지정될 수도 있다. 상수 값을 해당 타입의 값으로 표현할 수 없으면 오류이다. 타입이 타입 파라미터인 경우, 상수는 타입 파라미터의 상수가 아닌 값으로 변환된다.

 

 타입화되지 않은 상수의 케이스에는, 타입화된 값이 필요한 컨텍스트 (ex. 명시적 타입이 없는 i := 0 과 같은 짧은 변수 선언)에서 상수가 암시적으로 변환되는 타입인 기본 타입을 가진다. 타입이 지정되지 않은 상수의 기본 유형은 진리값 = bool, 룬 = rune, 정수 = int, 부동 소수점 = float64, 복소수 = complex128, 문자열 = string 이다.

 

구현 제한: 숫자 상수는 언어에서 임의의 정밀도를 갖지만 컴파일러는 정밀도가 제한된 내부 표현을 사용하여 이를 구현할 수 있습니다. 즉 모든 구현은 다음을 수행해야한다.

1. 최소 256비트의 정수 상수를 표현한다
2. 최소 256비트의 가수와 최소 16비트의 부호 있는 이진 지수를 사용하여 복소수 상수의 일부를 포함한 부동 소수점 상수를 표현한다
3. 정수 상수를 정확하게 표현할 수 없으면 오류를 발생시킨다
4. overflow로 인해 부동 소수점 또는 복소수 상수를 표현할 수 없으면 오류를 발생시킨다
5. 정밀도 제한으로 인해 부동 소수점 또는 복소수 상수를 표현할 수 없는 경우 가장 가까운 표현 가능한 상수로 반올림한다

이러한 요구 사항은 리터럴 상수와 상수기 평가 결과 모두에 적용된다.

 


변수 (Variables)

 

 변수는 값을 보관하기 위한 저장 위치이다. 허용되는 값 집합은 변수 유형에 따라 결정된다.

 

 변수 선언 또는, 함수 매개변수 및 반환값의 경우 함수 선언 / 함수 리터럴 서명은 명명된 변수에 대한 저장소를 예약한다. 내장 함수 new를 호출하거나 복합 리터럴의 주소를 가져오면 런타임에 변수에 대한 저장소가 할당된다. 이러한 익명 변수는 포인터 간접 참조를 통해 참조된다.

 

 배열, Slice 및 구조체 타입의 구조화된 변수에는 개별적으로 주소를 지정할 수 있는 요소와 필드가 있다. 이러한 각 요소는 변수처럼 작동한다.

 

 변수의 정적 타입 (또는 단순한 타입)은 선언에 제공된 타입, 새 호출 또는 복합 리터럴에 제공된 타입 또는 구조화된 변수의 요소 타입이다. 인터페이스 타입의 변수에는 고유한 동적 타입도 존재한다. 이는 런타임 시 변수에 할당된 값의 (인터페이스가 아닌) 타입이다 (값이 타입이 없는 미리 선언된 식별자 nil이 아닌 경우). 동적 타입은 실행 중에 달라질 수 있지만 인터페이스 변수에 저장된 값은 항상 변수의 정적 타입에 할당할 수 있다.

var x interface{}  // x is nil and has static type interface{}
var v *T           // v has value nil, static type *T
x = 42             // x has value 42 and dynamic type int
x = v              // x has value (*T)(nil) and dynamic type *T

 변수의 값은 표현식에서 변수를 참조하여 검색된다 (변수에 할당된 가장 최근 값을 기준으로 한다). 변수에 아직 값이 할당되지 않은 경우 해당 값은 해당 타입에 대한 Zero 값이다.

 


타입 (Types)

 

 타입은 해당 값과 관련된 연산 및 메서드와 함께 값 집합을 결정한다. 타입은 타입 이름이 있는 경우 타입 이름으로 표시할 수 있으며, 타입이 제네릭인 경우 타입 인수가 뒤에 와야한다. 기존 타입에서 타입을 구성하는 타입 리터럴을 사용하여 타입을 지정할 수도 있다.

Type      = TypeName [ TypeArgs ] | TypeLit | "(" Type ")" .
TypeName  = identifier | QualifiedIdent .
TypeArgs  = "[" TypeList [ "," ] "]" .
TypeList  = Type { "," Type } .
TypeLit   = ArrayType | StructType | PointerType | FunctionType | InterfaceType |
            SliceType | MapType | ChannelType .

 Golang은 특정 타입 이름을 미리 선언한다. 다른 언어들은 타입 선언이나 타입 매개변수 목록을 통해 소개된다. 배열, 구조체, 포인터, 함수, 인터페이스, 슬라이스, 맵 및 채널 타입과 같은 복합 타입은 타입 리터럴을 사용하여 구성할 수 있다.

 

 미리 선언된 타입, 정의된 타입 및 타입 매개변수를 명명된 타입이라고 한다. 별칭 선언에 제공된 타입이 명명된 타입인 경우 별칭은 명명된 타입을 나타낸다.

 


진리값 타입 (Boolean Types)

 

 진리값 타입은 미리 선언된 상수 true 및 false로 표시되는 bool 진리값 집합을 나타낸다. 예약어는 bool이고, 정의된 유형이다.

 


숫자 타입 (Numeric Types)

 

 정수, 부동 소수점 또는 복합 유형은 각각 정수, 부동 소수점 또는 복합 값 집합을 나타낸다. 이를 집합적으로 숫자 타입이라고 한다. 미리 선언된 아키텍처 독립적인 숫자 타입은 다음과 같다.

uint8       the set of all unsigned  8-bit integers (0 to 255)
uint16      the set of all unsigned 16-bit integers (0 to 65535)
uint32      the set of all unsigned 32-bit integers (0 to 4294967295)
uint64      the set of all unsigned 64-bit integers (0 to 18446744073709551615)

int8        the set of all signed  8-bit integers (-128 to 127)
int16       the set of all signed 16-bit integers (-32768 to 32767)
int32       the set of all signed 32-bit integers (-2147483648 to 2147483647)
int64       the set of all signed 64-bit integers (-9223372036854775808 to 9223372036854775807)

float32     the set of all IEEE-754 32-bit floating-point numbers
float64     the set of all IEEE-754 64-bit floating-point numbers

complex64   the set of all complex numbers with float32 real and imaginary parts
complex128  the set of all complex numbers with float64 real and imaginary parts

byte        alias for uint8
rune        alias for int32

 n 비트 정수의 값은 n 비트 너비이며 2의 보수 연산을 사용하여 표현된다.

 

 구현별 크기를 갖는 미리 선언된 정수 타입 집합도 있다.

uint     either 32 or 64 bits
int      same size as uint
uintptr  an unsigned integer large enough to store the uninterpreted bits of a pointer value

 이식성 문제를 방지하기 위해, 모든 숫자 타입은 정의된 타입이므로 unit8의 별칭인 byte와 int32의 별칭인 rune을 제외하고는 고유하다. 표현식이나 할당에 서로 다른 숫자 타입이 혼합되어 있는 경우 명시적 변환이 필요하다. 예를 들어, int32와 int는 특정 아키텍처에서 동일한 크기를 가질 수는 있어도, 동일한 타입은 아니다.

 


문자열 타입 (String Types)

 

 문자열 타입은 문자열 값 집합을 나타낸다. 문자열 값은 (비어 있을 수도 있는) byte sequence 이다. 바이트 수는 문자열의 길이라고 하며 결코 음수가 될 수 없다. 문자열은 변경할 수 없다(immutable). 일단 생성되면 문자열의 내용을 변경할 수는 없다. 예약어는 string 이다.

 

 문자열 s의 길이는 내장 함수 len을 사용하여 알아낼 수 있다. 문자열이 상수인 경우 길이는 컴파일 타임 상수이다. 문자열의 바이트는 정수 인덱스 0부터 len(s)-1까지 액세스할 수 있다. 이외 인덱스의 주소를 가져오는 것은 허용되지 않는다: s[i]가 문자열의 i번째 바이트이면 &s[i]는 유효하지 않다.

 


배열 타입 (Array Types)

 

 배열은 요소 타입이라고 하는 단일 타입 요소에게 번호가 매겨진 시퀀스이다. 요소의 수는 배열의 길이라고 하며 결코 음수가 될 수 없다.

ArrayType   = "[" ArrayLength "]" ElementType .
ArrayLength = Expression .
ElementType = Type .

 길이는 배열 타입의 일부분이다. 따라서 int 타입 값으로 표현 가능한, 음수가 아닌 상수로 평가되어야한다. 배열 a의 길이는 내장 함수 len을 사용하여 알아낼 수 있다. 요소는 정수 인덱스 0부터 len(a)-1까지 주소를 지정할 수 있다. 배열 타입은 항상 1차원이지만 다차원 타입을 형성하도록 구성될 수 있다.

[32]byte
[2*N] struct { x, y int32 }
[1000]*float64
[3][5]int
[2][2][2]float64  // same as [2]([2]([2]float64))

 배열 타입 T에는 T 타입의 요소 또는 T를 구성 요소로 포함하는 타입의 요소가 포함되지 않을 수 있다. (포함하는 타입이 배열 또는 구조체 유형인 경우)

// invalid array types
type (
	T1 [10]T1                 // element type of T1 is T1
	T2 [10]struct{ f T2 }     // T2 contains T2 as component of a struct
	T3 [10]T4                 // T3 contains T3 as component of a struct in T4
	T4 struct{ f T3 }         // T4 contains T4 as component of array T3 in a struct
)

// valid array types
type (
	T5 [10]*T5                // T5 contains T5 as component of a pointer
	T6 [10]func() T6          // T6 contains T6 as component of a function type
	T7 [10]struct{ f []T7 }   // T7 contains T7 as component of a slice in a struct
)

 


슬라이스 타입 (Slice Types)

 

 슬라이스는 기본 배열의 연속 세그먼트에 대한 설명자이며 해당 배열에서 번호가 매겨진 요소 시퀀스에 대한 액세스를 제공한다. 슬라이스 타입은 해당 요소 타입의 모든 배열 슬라이스 집합을 나타낸다. 요소의 수는 슬라이스의 길이라고 불리며 결코 음수가 아니다. 초기화되지 않은 슬라이스의 값은 nil이다.

SliceType = "[" "]" ElementType .

 슬라이스 s의 길이는 내장 함수 len으로 알아낼 수 있다. 배열과 달리 실행 중에 변경될 수 있다. 요소는 정수 인덱스 0부터 len(s)-1까지 주소를 지정할 수 있다. 특정 요소의 슬라이스 인덱스는 기본 배열에 있는 동일한 요소의 인덱스보다 작을 수 있다.

 

 일단 초기화된 슬라이스는 항상 해당 요소를 보유하는 기본 배열과 연결된다. 따라서 슬라이스는 해당 배열 및 동일한 배열의 다른 슬라이스와 스토리지를 공유한다. 반대로, 개별 배열은 항상 개별 스토리지를 나타낸다.

 

 슬라이스 아래에 있는 배열은 슬라이스의 끝을 지나 확장될 수 있다. 용량은 해당 범위의 척도이다. 이는 슬라이스 길이와 슬라이스를 넘어선 배열 길이의 합이다. 원본 슬라이스에서 새 슬라이스를 잘라 해당 용량까지 길이의 슬라이스를 만들 수도 있다. 슬라이스 a의 용량은 내장 함수 cap(a)를 사용하여 확인할 수 있다.

 

 주어진 요소 타입 T에 대해 초기화된 새로운 슬라이스 값은 내장 함수 make를 사용하여 만들 수 있다. 이 함수는 슬라이스 유형과 길이 및 선택적으로 용량을 지정하는 매개변수를 사용한다. make로 생성된 슬라이스는 항상 반환된 슬라이스 값이 참조하는 새로운 숨겨진 배열을 할당한다.

 

make([]T, length, capacity)

// 그러므로, 아래 두 함수는 같은 값을 가진다.
make([]int, 50, 100)
new([100]int)[0:50]

 배열과 마찬가지로 슬라이스는 항상 1차원이지만 더 높은 차원의 개체를 구성하도록 구성될 수 있다. 배열의 배열의 경우, 내부 배열의 길이는 항상 동일하다. 그러나 슬라이스의 슬라이스의 경우 내부 길이가 동적으로 달라질 수 있다. 또한 내부 슬라이스는 개별적으로 초기화되어야 한다.

 


구조체 타입 (Struct Types)

 

 구조체는 필드라고 하는 명명된 요소의 시퀀스이며 각 요소에는 이름과 타입이 존재한다. 필드 이름은 명시적으로 (IdentifierList) 혹은 암시적으로 (EmbeddedField) 지정될 수 있다. 구조체 내에서 비어있지 않은 필드 이름은 고유해야 한다.

StructType    = "struct" "{" { FieldDecl ";" } "}" .
FieldDecl     = (IdentifierList Type | EmbeddedField) [ Tag ] .
EmbeddedField = [ "*" ] TypeName [ TypeArgs ] .
Tag           = string_lit .
// An empty struct.
struct {}

// A struct with 6 fields.
struct {
	x, y int
	u float32
	_ float32  // padding
	A *[]int
	F func()
}

 

 타입으로 선언되었지만 명시적인 필드 이름이 없는 필드를 Embedded 필드라고 한다. Embedded 필드는 타입 이름 T 또는 비 인터페이스 타입 이름 *T 에 대한 포인터로 지정되어야 하며 T 자체는 포인터 유형이 아닐 수 있다. 규정되지 않은 타입 이름은 필드 이름 역할을 한다.

// A struct with four embedded fields of types T1, *T2, P.T3 and *P.T4
struct {
	T1        // field name is T1
	*T2       // field name is T2
	P.T3      // field name is T3
	*P.T4     // field name is T4
	x, y int  // field names are x and y
}

 

 필드 이름은 구조체 타입에서 고유해야 하므로, 다음 선언은 올바르지 않다.

struct {
	T     // conflicts with embedded field *T and *P.T
	*T    // conflicts with embedded field T and *P.T
	*P.T  // conflicts with embedded field T and *T
}

 

  x.f가 해당 필드 또는 메서드 f를 나타내는 유효한 선택자인 경우 구조체 x에 포함된 필드의 필드 또는 메서드 f를 승격( promoted) 이라고 한다.

 

 승격된 필드는 구조체의 복합 리터럴에서 필드 이름으로 사용할 수 없다는 점을 제외하면 구조체의 일반 필드처럼 작동한다.

 

 구조체 타입 S와 명명된 타입 T 가 주어지면 승격된 메서드는 다음과 같이 구조체의 메서드 집합에 포함된다.

  • S에 포함된 필드 T 가 포함된 경우 S 및 *S의 메서드 집합에는 모두 수신기 T가 포함된 승격된 메서드가 포함된다. *S의 메서드 집합에는 수신기 *T가 포함된 승격된 메서드도 포함된다.
  • S에 포함된 필드 *T가 포함된 경우 S 및 *S의 메소드 집합에는 모두 수신자 T 또는 *T가 있는 승격된 메소드가 포함된다.

 필드 선언 뒤에는 해당 필드 선언의 모든 필드에 대한 속성이 되는 선택적 문자열 리터럴 태그가 올 수 있다. 빈 태그 문자열은 태그가 없는 것과 동일하다. 태그는 Reflection Interface를 통해 표시되고 구조체의 타입 ID에 참여하지만 그렇지 않으면 무시된다.

 

struct {
	x, y float64 ""  // 빈 태그 문자열은 없는 태그와 같다.
	name string  "어떠한 문자열도 태그로써 허용된다"
	_    [4]byte "이것은 구조 필드가 아니다"
}

// TimeStamp 프로토콜 버퍼에 해당하는 구조체이다.
// 태그 문자열은 프로토콜 버퍼 필드 번호를 정의한다.
// Reflect 패키지에 설명된 규칙을 따른다.
struct {
	microsec  uint64 `protobuf:"1"`
	serverIP6 uint64 `protobuf:"2"`
}

 

 구조체 타입 T는 T 타입의 필드 또는 T를 구성 요소로 포함하는 유형의 필드를 직접 또는 간접적으로 포함할 수 없다(포함하는 타입이 배열 또는 구조체 유형인 경우).

// invalid struct types
type (
	T1 struct{ T1 }            // T1 contains a field of T1
	T2 struct{ f [10]T2 }      // T2 contains T2 as component of an array
	T3 struct{ T4 }            // T3 contains T3 as component of an array in struct T4
	T4 struct{ f [10]T3 }      // T4 contains T4 as component of struct T3 in an array
)

// valid struct types
type (
	T5 struct{ f *T5 }         // T5 contains T5 as component of a pointer
	T6 struct{ f func() T6 }   // T6 contains T6 as component of a function type
	T7 struct{ f [10][]T7 }    // T7 contains T7 as component of a slice in an array
)

 


포인터 타입 (Pointer Type)

 

 포인터 타입은 포인터의 기본 타입이라고 하는 특정 타입의 변수에 대한 모든 포인터 집합을 나타낸다. 초기화되지 않은 포인터의 값은 nil이다.

PointerType = "*" BaseType .
BaseType    = Type .
*Point
*[4]int

 


함수 타입 (Function Types)

 

 함수 타입은 동일한 매겨변수 및 결과 유형을 갖는 모든 함수의 집합을 나타낸다. 함수 타입의 초기화되지 않은 변수 값은 nil이다.

FunctionType   = "func" Signature .
Signature      = Parameters [ Result ] .
Result         = Parameters | Type .
Parameters     = "(" [ ParameterList [ "," ] ] ")" .
ParameterList  = ParameterDecl { "," ParameterDecl } .
ParameterDecl  = [ IdentifierList ] [ "..." ] Type .

 

 매개변수 혹은 반환값 목록 내에서 이름 (IdentifierList)은 모두 존재하거나 모두 없어야 한다. 존재하는 경우 각 이름은 지정된 타입의 하나의 항목(매개변수 또는 결과)을 나타내며 서명에 있는 공백이 아닌 모든 이름은 고유해야 한다. 없는 경우 각 타입은 해당 타입의 한 항목을 나타낸다. 매개변수 및 반환값 목록은 이름이 지정되지 않은 결과가 정확히 하나만 있는 경우 괄호가 없는 없는 타입으로 작성될 수 있다는 점을 제외하고 항상 괄호로 묶인다.

 

 함수 시그니처의 최종 수신 매개변수에는 ... 라는 접두사가 붙은 타입이 있을 수 있다. 이러한 매개변수가 있는 함수를 variadic이라고 하며 해당 매개변수에 대해 0개 이상의 인수를 사용하여 호출할 수 있다.

func()
func(x int) int
func(a, _ int, z float32) bool
func(a, b int, z float32) (bool)
func(prefix string, values ...int)
func(a, b int, z float64, opt ...interface{}) (success bool)
func(int, int, float64) (float64, *[]int)
func(n int) func(p *T)

 

 


정리

 

 지금까지 타입에 관한 내용을 정리해보았다. 이후에 남은 타입들은 인터페이스를 포함한 내용이기 때문에, 묶어서 정리하는 편이 좋을 것 같아서 다음 글에 같이 정리해볼 예정이다.

반응형

'Golang' 카테고리의 다른 글

Golang 입문기 - 문법 4  (2) 2024.02.11
Golang 입문기 - 문법 3  (2) 2023.11.20
Golang 입문기 - 문법 1  (2) 2023.10.24
Golang 입문기 - 0  (0) 2023.10.20