Golang Basic 상수 const 키워드 사용 const 키워드를 생략할 수 없기 떄문에 ‘:=’ 이용한 타입 추론 불가능. 괄호로 여러개 상수를 묶어 초기화 가능(상수 선언간 개행 필요.) const ( val1 = 1 val2 = 2 ) 증감연산자 전위 연산자 사용 불가능 정수, 실수, 복소수에 대해 증감 연산 가능 논리연산자 bool형(true,false)에 대해서만 논리 연산 가능, 다른 언어 처럼 1과 0에 대해서 논리연산 불가능. 포인터 C처럼 포인터 사용 가능. & (메모리 주소 참조), *(메모리에 접근, 값 참조) 포인터 산술 연산은 제공하지 않음… 그럼 뭐에다 쓰려고… 자료형 Sizeof Unsafe 패키지의 Sizeof 함수로 타입 size 확인 가능 Boolean Type 1 Byte Go에서는 true와 false만 사용하여 값 할당 Integer Type 32bit 시스템에서 32비트, 64bit 시스템에서 64비트 int8, int16, int32, int64, uint8 … uintptr(8Byte) uintptr은 포인트 주소 할당할 때 주로 사용. Floating Point Type float32, float64 문자열 타입 16 Byte string으로 선언한 문자열 타입은 immutable 타입으로, 값 수정 불가능 etc. byte (1Byte), 바이트 값을 8bit uint와 구별해 사용 rune (4Btye), 문자 값을 정수 값과 구별하기 위해 사용 자료형 Casting 명시적 형변환 해줘야함 var str string = "Hello" changeStr := []byte(str) // string -> byte 배열 str2 := string(changeStr) for Golang은 while 지원하지 않음. 오로지 for 기본 형태 for i:= 0 ; i < n; i++ { ... } 무한 loop for { ... } for range foreach와 비슷, for index, 요소값 := range 컬렉션 이름 조건, 제어문 Only True, False, Not 1,0 Go에서는 조건문 한 줄일때도 중괄호 생략 불가능 괄호 시작과 else문 같은 줄에. Break, Continue, Goto break, continue 키워드로 사용 가능 break문 뒤에 레이블과 같이 사용되면 지정된 레이블로 이동 가능 func main() { i := 0 LABEL1: for { if i == 0 { break LABEL1 } } // break문이 바로 빠져나왔던 for문 다음 문장 실행 fmt.Println("End") goto LABEL1 } Collection Go에서 두 개 이상의 변수를 모아 놓은 것을 컬렉션이라.. Array Go에서 배열은 정적. 고정된 크기. 그래서 배열 크기를 동적으로 사이징하거나 부분 배열만 가져오는 기능은 없다. 배열의 크기는 자료형을 구성하는 하나의 요소로, 2[int]와 3[int]는 자료형 자체가 다른 것이다. var arrName [사이즈]자료형 자바나 C++처럼 배열 크기를 데이터 타입 앞에 쓰는 방식 안됨. func main(){ var arr1 [5]int fmt.Println(arr1) // [0 0 0 0 0] 출력 arr2 := [5]int{1, 2, 3, 4, 5} // type 추론 가능 fmt.Println(arr1) // [1 2 3 4 5] var arr3 = [...]int{9, 8, 7, 6} // [...] 이용해 배열 크기 자동 설정 fmt.Println(len(arr3)) // 4 } Slice Go에서 배열은 필요에 따라 동적으 크기를 증가시키는 등의 기능을 가지고있지 않다. Slice는 배열과 다르게 고정된 크기를 미리 지정하지 않아도 필요에 따라 크기를 동적으로 변경할수 있고 부분 추출이 가능하다. Slice는 초기화하지 않아도 배열 위치를 가리키는 ptr, 배열 길이 len, 용량인 cap 변수를 위한 메모리를 가지고 있다. Slice는 참조 타입, 참조하고 있는 slice의 값을 변경하게 되면? func main(){ var a []int a = []int{1,2,3,4,5} a[0] = 10 a[1] = 20 a[2] = 30 a[3] = 40 a[4] = 50 b := a[2:4] b[1]= 45 fmt.Println(a) // [10 20 30 45 50] 출력 } make() make(type, length, capacity) 형태로 선언 func main(){ a := make([]int, 0, 2) for i:=0 ; i < 9 ; i++ { a = append(a, i) fmt.Println("len :", len(a), "cap :", cap(a)) } } output len : 3 cap : 4 len : 4 cap : 4 len : 5 cap : 8 len : 6 cap : 8 len : 7 cap : 8 len : 8 cap : 8 len : 9 cap : 16 slice에 메모리 공간이 추가될 때마다 다른 메모리에 기존+새로운 공간 크기만큼의 메모리를 할당하고 원본을 복사하는식으로 동작하는데, 매번 공간 할당과 원본 데이터를 복사하면 비효율적이기 때문에 capacity를 두배씩 늘려주는게 아닌가 싶은데, 기초다지고 다시 알아보기로. append()로 slice에 slice 추가 가능 sliceA := []int{1,2} sliceB := []int{4,5} slice A = append(sliceA, sliceB...) copy() func main(){ sliceA := []int{0,1,2,3,5,6,7} sliceB := make([]int, len(sliceA), cap(sliceA)*2) copy(sliceB, sliceA) sliceC := sliceB[2:4] // 범위 복 sliceD := sliceB[3:] //인덱스 3부터 끝까지 복사 } Map Slice 처럼 참조타입 var apName map[keyType]valType 선언만하고 초기화하지 않았다면 Nil map func main() { var mp map[int]string if mp == nil{ fmt.Println("nil map") } var mp2 = map[string]string{ "foo": "bar", "bar": "foo", } “mapName[key] = value” 형식으로 값 추가 가능, key 존재한다면 갱신됨 “delete(mapName,key)”로 key에 매칭되는 value 삭제 Map의 Key 체크 “mapName[key]”는 key에 저장된 값을 반환할 뿐만 아니라, 해당 키에 값이 존재하는지 안 하는지 여부도 함께 반환. console 출력 함수에 mapName[key]를 입력할 때는 key값에 해당하는 value 값만 출력 value값과 true/false 값을 반환하기 위해서는 변수 두 개를 선언한 후에 각각 할당 받아야함. value 값만 반환받으려면 변수 한 개만 선언해 할당 받으면 된다. key 포함 여부만 반환 받으려면 “_, bool변수” 형식으로 받으면됨 func main(){ var mp = make(map[string]string) mp["02"] = "Seoul" mp["031"] = "Kyeogki" mp["053"] = "Daegu" val, exist := mp["02"] val = mp["053"] // value만 반환 _, exist = mp["053"] // true, false만 반환 } 클로저 함수 안에서 익명 함수를 정의해서 바깥쪽 함수에 선언한 변수에도 접근할 수 있는 함수 func main(){ a, b:= 10, 20 str := "Hello" result := func() int { return a+b }() func() { fmt.Println(str) }() fmt.Println(result) } 함수 안세어 함수를 정의하기 위해서 익명 함수만 사용 가능. main() 함수 내에 선언된 익명 함수들이 main() 함수의 변수를 파라미터 없이 접근. func next() func() int { i := 0 return func() int { i += 1 return i } } func main() { nextInt := next() fmt.Println(nextInt()) fmt.Println(nextInt()) fmt.Println(nextInt()) nextInt := next() fmt.Println(nextInt()) } // 1 2 3 1 출력 next 함수는 i 변수를 1씩 증가시키는 익명 함수를 반환. 따라서 nextInt를 실행할 때마다 값이 초기화 되지 않고 이전 컨택스트에서 i 값을 1 증가 시킴. 구조체, 메소드 Golang은 객체 지향이지만 전통적인 객체 지향 언어의 Class, Onject, Inheritance 개념 없이, 유사한테로 따름. Golang에서 클래스는 Custom 타입을 정의하는 구조체에 필드만을 표현하고, 메소드는 따로 분리하여 정의함. type perseon struct { name string age int contact string } func main(){ var p = person{} p.name = "lee" p.age = 29 p.contatct = "010-9999-9999" p2 := person{"kim", 29, "010-9999-8888"} } golang의 구조체는 ‘mutable’ 개체로 필드 값 변경시 별도의 새 개체를 만들지 않고 해당 개체 메모리에서 변경 func addAgeRef(pp *person) { // pass by ref pp.age += 1 //자동 역참조 * 생략 } func addAgeVal(p person) { // pass by val p.age += 1 } func main(){ var pp = new(person) // 포인터 구조체 객체 생성 pp.age = 29 addAgeRef(pp) // &을 쓰지 않아도됨 fmt.Println(pp.age) var p = person{} p.age = 29 addAgeVal(p) fmt.Println(p.age) addAgeRef(&p) // &로 주소 넘기면 pass by ref 가능 fmt.Println(p.age) } 구조체 포인터 생성 방법 1. ‘new(구조체이름)’, 2. 구조체 이름 앞에 & 붙이기 포인터 구조체는 선언시 자동으로 역참조되어, 함수 내에서 * 연산자를 사용할 필요가 없음. 생성자(Constructor) 함수 구조체 필드 자체가 사용 전에 초기화되어햐 하는 경우를 위해 ‘생성자 함수’를 사용할 수 있음. 생성자 함수는 구조체 객를 생성하고 초기화한 구조체를 반환 type mapStruct struct{ mapData map[int]string } func newStruct() *mapStruct { d := mapSturct{} d.mapData = map[int]string{} return &d }