참고 자료
1. https://go.dev/blog/declaration-syntax
2. https://go.dev/tour/basics/12
3. https://go.dev/tour/moretypes/1
4. https://soyoja.com/263 : 비트 이동 연산자
Go 와 C syntax가 다른 이유에 대해서
C syntax는 declare할 때 그것이 앞으로 가지게 될 type을 명시하는 형태이다. int x; 와 같이 x는 int 일 것임을 declare하는 것이다.
int *p; *p가 int라는 것. p가 int를 향한 pointer라는 것을 의미한다.
int a[2]; a[2]가 int type을 가지기 때문에 a는 int의 array임을 의미한다.
함수의 경우에는
paren 바깥에서 arguments 의 타입들을 명시했지만, modern notation에서는 아래와 같이 명시한다.
int main(int argc, char *argv[]) { /* ... */ }
이런식으로 명시하는 경우 빠르게 혼란스러워진다. 유명한 예시는 function pointer가 있다. 읽어서 해독하기가 어려워 진다.
Go syntax의 경우 이제 x int / p *int / a [3]int 이런식으로 선언이된다. left->right방향으로 읽히기 때문에 더 읽기 쉬워진다.
또한 type과 expression syntax 사이의 구분이 closure를 쓰고, 부르기를 쉽게 할 수 있다.
sum := func(a, b int) int { return a+b } (3, 4)
Go의 type syntax 는 bracket을 타입의 왼쪽에 놓는다. Go의 pointer 는 C처럼 * 를 쓰는데, *를 앞쪽에 쓰는 이유는 multiplication과 헷갈리기 때문.
Variable 관련
var statement는 한개 이상의 variables를 선언할 수 있다. function arguments에서 x int, y int 를 x, y int로 줄여 쓸 수 있는 것처럼 여러개를 선언하고 type을 마지막에 쓴다.
만약에 vaiable 에 initializer가 있다면, type을 쓰지 않아도 된다. initializer의 type을 가지게 된다.
Short variable declarations
함수 안에서 := 를 사용해서 var 대신 사용 할 수 있다. 함수 밖에서는 keyword(var, func, 등) 을 사용해야 가능하다 .
:= 는 결국 right hand side가 typed가 되면 새로운 variable이 같은 타입을 가지게 되는 것이다. 만약에 untyped numeric constant가 오른쪽에 오면, constant의 precision을 사용해서 결정된다.
Zero value : numeric이면 0, boolean이면 false, string이면 ""
Type conversions: T(v) 는 v를 type T로바꿔준다. C와 다르게, Go는 다른 type을 가지는 경우 explicit conversion을 필요로 한다. float value를 var z uint = f 이런식으로 automatic conversion을 제공하지 않는다는 것.
constants 같은 경우는 := syntax를 사용해서 불가능하고, variable 선언하는 것처럼 가능하다.
More Types
*T는 T의 pointer이다. zero value는 nil이다.
var p *int
*operator를 사용해서 pointer의 underlying value를 나타낸다.
i:=42; p=&i; &operator는 pointer를 generate한다.
*p = 21 이런식으로 p를 통해서 i의 값을 바꿀수도 있다. C와 다르게 pointer arithmetic을 지원하지 않음.
Pointer to struct : struct field 또한 pointer로 접근 가능하다. 주소를 통해 값에 접근하는 것을 dereference, 역참조라고 한다. 보통 이제 값에 접근하기 위해서는 (*p).X로 접근할 수 있지만, explicit dereference 없이도 가능하도록 허용한다.
v := Vertex{1,2} // 이 때 subset of fields만 사용해도 된다. Vertex{X: 1} -> Y:0 is implicit
p := &v
p.X = 1e3
Arrays : array의 길이가 array 타입의 일부이기 때문에 resized될 수 없다.
var a [2]string // 2개의 string value들을 가진 array
primes := [6]int{2,3,5,7,11,13}
Slices: array는 fixed size를 가지고 있지만, slice는 dynamically-sized된다. array를 참조하는데, flexible view를 제공하는 것과 같다. reference와 비슷해서, 아무 data를 저장하지 않고, 값을 바꾸면 해당 underlying array의 값이 바뀌고, 마찬가지로 같은 aray를 참조하는 slice도 그 변화를 볼 수 있다. 아래와 같이 정의한다면, 이는 결국 [3]bool{true, true, false}를 만들고 그것을 참조하는 slice를 만드는 것과 같다.
[]bool{true, true, false}
slice 의 zero value는 nil 이다. var s []int 일 때, s == nil true이다. built-in make 함수를 사용해서 slice를 만들 수 있다.
slice의 capacity는 slice의 첫번째 element 부터 시작해서 underlying arry의 element 갯수이다. len(s)는 slice안에 들어있는 element 개수 이다. capacity가 충분하다면 reslice를 해서 slice의 길이를 extend할 수 있다. extend할 때 s[:늘리고자 하는 길이] 를 사용하면 된다.
a := make([]int, 5) // len(a): 5, cap(a): 5
board := [][]string{
[]string{"_", "_", "_"},
[]string{"_", "_", "_"},
[]string{"_", "_", "_"},
} // 2d array
Appending to a slice: s = append(s, 1) -> 1을 뒤에 붙이게 됨.
Range: two values are returned for each iteration. index만 원한다면 for i := range pow, 를 사용하면 된다. pow는 여기서 slice.
Maps : zero value of a map 은 nil이다.
var m map[string]Vertex
m = make(map[string]Vertex) //make function returns map of the given type, initialized and ready to use
var m = map[string]Vertex{
"Bell Labs": {3.4, 2.3},
"Google": {3.2, 2.3},
}
Mutating Maps
m[key] = elem // insert or update an element
elem = m[key] //retrieve
delete(m, key) // delete
elem, ok = m[key] //if key is in m, ok is true
이 떄, elem, ok가 이미 declared되어 있지 않다면 short declaration form 으로 선언을 할 수 있다.
예제: https://go.dev/tour/moretypes/23
Function
- Functions 또한 value이다. 다른 value처럼 전달이 가능하다.
- Function closures: closure 는 body밖에 있는 variable을 참조하는 fucntion value를 의미한다. function이 그 변수에 bind되어있다고 볼 수 있다.
Function 을 variable 처럼 사용할 때 아래처럼 사용 가능하다.
f := func(x, y float64) float64 {
return math.Sqrt(x*x + y*y)
}
갑자기 비트연산자 관련 공부
<< n은 n만큼 왼쪽으로, >> n 은 n비트 만큼 오른쪽으로 비트를 이동한다.
int n = 1;
n = << 1; 이면 1만큼 왼쪽으로 이동하니까 2가 된다.
ex1) int n = 1; n=<<31; -> n : 2^32
ex2) n =<<32; 는 n=<<0 과 같으므로 1
ex3) n =<< 33; 는 n=<<1 과 같으니까 2
ex4) 32 bit -> -2 를 =<<31 하면 좌측이동하고 0으로 채운다. 이때 << 는 피 연산자가 양수나 음수인 경우 모두 0으로 자리를 채우는 반면, >> 는 양수일 경우에는 0으로 채우고, 음수이면 1로 채운다.
>>, << 모두 아래 5비트에 해당하는 32 까지만 이동한다. 33이면 1과 같아지는 원리.
'Backend with Golang' 카테고리의 다른 글
MySQL - Transaction (0) | 2023.05.09 |
---|---|
Docker-compose.yml 파일 작성하기 (TBU) (0) | 2023.05.09 |
Go: JSON (0) | 2023.05.03 |
Goroutine (0) | 2023.05.01 |
Docker 기본 개념 (1) | 2023.04.26 |