GoLang 문법 간단 정리
🙈

GoLang 문법 간단 정리

Created
May 27, 2024 03:56 AM
Last edited time
Last updated May 28, 2024
Tags
Language
Language
GoLang
URL

Intro::

GoLang 문법에 대해 알아봅시다

변수, 상수

package main import "fmt" func main() { // var 선언 var i1 int = 10; var s1 string = "string"; fmt.Println(i1); fmt.Println(s1); // 타입 생략 가능 var i2 = 10 var s2 = "string"; fmt.Println(i2); fmt.Println(s2); // := 를 이용한 변수 선언 i3 := 10 s3 := "string" fmt.Println(i3) fmt.Println(s3) // 다수의 변수를 동시에 선언 var i4, j4, k4 int = 10, 11, 12; s4, t4, u4 := "string1", "string2", "string3"; fmt.Println(i4, j4, k4); fmt.Println(s4, t4, u4); // var()를 이용한 변수 선언 var ( i7 = 1; j8 = 2; k9 = 3; s10, s11, s12 = "string1", "string2", "string3"; ); fmt.Println(i7, j8, k9); fmt.Println(s10, s11, s12); }
 

데이터 타입 변환

package main import ( "fmt" "reflect" "strconv" ) func main() { strInt := "100"; intStr := string(strInt); fmt.Println(intStr, reflect.TypeOf(intStr)); i, err := strconv.Atoi(strInt); fmt.Println(i, err, reflect.TypeOf(i)); strInt = "987654321"; i8, err := strconv.ParseInt(strInt, 0, 8); i16, err := strconv.ParseInt(strInt, 0, 16); i32, err := strconv.ParseInt(strInt, 0, 32); i64, err := strconv.ParseInt(strInt, 16, 64); fmt.Println(i8, err, reflect.TypeOf(i8)); // 127 <nil> int64 fmt.Println(i16, err, reflect.TypeOf(i16)); // 32767 <nil> int64 fmt.Println(i32, err, reflect.TypeOf(i32)); // 987654321 <nil> int64 fmt.Println(i64, err, reflect.TypeOf(i64)); // 40926266145 <nil> int64 }
 

if, switch 문

package main import ( "fmt" "math/rand" "os" "time" ) func main() { // if 사용 seed := time.Now().UnixNano(); randSource := rand.NewSource(seed); random := rand.New(randSource); i := random.Intn(15); fmt.Println(i); if i < 10 { fmt.Println("A"); } else if i == 10 { fmt.Println("B"); } else { fmt.Println("C"); } // -------- if condition ----------- str := "Hello World!"; filePath := "hello.txt"; if _, err := os.Stat(filePath); err == nil { // 파일이 존재하면 삭제 err := os.Remove(filePath); if err != nil { fmt.Println("파일 삭제 중 오류 발생:", err); } else { fmt.Println("파일이 성공적으로 삭제되었습니다."); } } else if os.IsNotExist(err) { // 파일이 존재하지 않음 fmt.Println("파일이 존재하지 않습니다."); } else { // 다른 오류 발생 fmt.Println("파일 상태 확인 중 오류 발생:", err); } if err := os.WriteFile("hello.txt", []byte(str), 0644); err != nil { fmt.Println(err); } fmt.Println("======================================================="); random = rand.New(randSource); i = random.Intn(15); fmt.Println(i) switch i { case 0, 1: fmt.Println("A") case 2, 3, 4: fmt.Println("B") case 5: fmt.Println("C") default: fmt.Println("D") } }
 

for, range 문

range 문은 array, slice, map의 내용을 반복하는데 많이 사용한다. range문은 반복을 처리하기 전에 객체를 복사해서 사용합니다. 따라서 객체의 값을 반복문 안에서 변경해도 실제 값은 변경되지 않습니다. 때문에 실제 객체값을 변경하고자 한다면 포인터를 이용해서 작업을 처리해야합니다.
package main import ( "fmt" ) type Obj struct { Name string Age int } func PrintObject(list []Obj) { for index, object := range list { fmt.Printf("index: %d, object: %+v\n", index, object) } } func main() { // for 문은 기본 형식과 while 문 형식으로 사용 가능하다. for index := 1; index <= 10; index++ { fmt.Printf("index: %d\n", index) } index := 1 for true { fmt.Printf("index: %d\n", index) if index >= 10 { break } index++ } // for, range 문(foreach 형식) arr := []string{"A", "B", "C"} for i, str := range arr { fmt.Printf("i: %d, str: %s\n", i, str) } dictionary := map[string]string{ "key_A": "value_A", "key_B": "value_B", } for key, value := range dictionary { fmt.Printf("key: %s, value: %s\n", key, value) } // range loop 객체 list := []Obj{ {"Beckham", 11}, {"Zidane", 7}, {"Ronaldo", 9}, } for _, object := range list { object.Age = object.Age * 2 } // 출력, 11, 7, 9 PrintObject(list) for index := range list { object := &list[index] object.Age = object.Age * 2 } // 출력, 22, 14, 18 PrintObject(list) }
 

함수

다른 언어와 동일하고 몇가지 특이사항이 있다.
  • slice 파라미터 호출
  • 다중값 반환
  • 익명 함수
  • 일급 함수
package main import ( "fmt" "strings" ) func changeValue(message *string) { *message = fmt.Sprintf("your name is %s", *message) } func addTen(value int) int { return value + 10 } // ... 은 slice 로 값을 받음 func sum(values ...int) int { result := 0 for _, value := range values { result = result + value } return result } func divideStrings(value string) (string, string) { values := strings.Split(value, "_") return values[0], values[1] } func calc(f func(int, int) int, a int, b int) int { result := f(a, b) return result } func main() { // 함수 호출 fmt.Println(addTen(100)) // slice 변수 호출 fmt.Println(sum(1, 2, 3, 4, 5)) // 다중 변수 반환 prefix, suffix := divideStrings("Your_Name") fmt.Println(prefix, suffix) // 포인터 전달 message := "Ronaldo" changeValue(&message) fmt.Println(message) // 익명 함수 sum := func(x int, y int) int { return x + y } fmt.Println(sum(5, 10)) // 일급 함수 add := func(i int, j int) int { return i + j } minus := func(i int, j int) int { return i - j } fmt.Println(calc(add, 10, 5)) fmt.Println(calc(minus, 10, 5)) }
 

배열

배열은 길이가 고정된 형태로 선언되고, 다차원 배열을 이용할 수 있습니다.
package main import "fmt" func main() { // 배열 선언 var intArray [3]int intArray[0] = 3 intArray[1] = 4 intArray[2] = 6 // 선언과 동시에 초기화 var stringArrayWithInit = [3]string{"A", "B", "C"} for index := range stringArrayWithInit { fmt.Printf("%s\n", stringArrayWithInit[index]) } // 멀티플 배열 var intMultipleArray = [2][3]int{ {3, 4, 5}, {6, 7, 8}, } for x := range intMultipleArray { for y := range intMultipleArray[x] { fmt.Println(intMultipleArray[x][y]) } } }
 

슬라이스

슬라이스는 배열과 비슷하지만 몇 가지 장점이 있다.
  • 크기를 지정하지 않고 생성 할 수 있음
  • 크기를 동적으로 증가 시킬 수 있음(용량이 부족하면 현재 용량의 두배 증가)
  • 부분 배열을 추출 할 수 있음
사용함에 편의성을 제공하기 때문에 배열보다는 슬라이스를 이용하는 것을 추천하고 있다.
 
  • 슬리이스 생성은 배열과 동일하지만, 사이즈가 없으면 슬라이스
    • 배열: [5]int, 슬라이스: []int
  • make를 이용해서 생성할 때는 length, capacity 를 입력하고 생성
  • append를 이용해서 추가하면 현재 length 뒤에 추가 됨
  • copy를 이용해서 현재 내용 복사 가능
  • 인덱스를 이용해서 슬라이스의 내용을 추출 가능
 
package main import "fmt" func main() { // 슬라이스 생성 letters := []string{"a", "b", "c", "d"} fmt.Println(letters, cap(letters)) // [a b c d] // make 를 이용한 slice 생성 s1 := make([]int, 0) fmt.Println(s1, len(s1), cap(s1)) // [] 0 0 s2 := make([]int, 5) fmt.Println(s2, len(s2), cap(s2)) //[] 0 5 s3 := make([]int, 3, 5) fmt.Println(s3, len(s3), cap(s3)) //[0 0 0] 3 5 // append // append는 len으로 설정한 값 뒤에 추가 됨 intArray := []int{100, 101, 102} s1 = append(s1, 100) s2 = append(s2, intArray...) // 슬라이스 끼리 더할 때는 ... 을 추가 s3 = append(s3, 100, 101, 102) fmt.Println(s1, len(s1), cap(s1)) // [100] 1 1 fmt.Println(s2, len(s2), cap(s2)) // [0 0 0 0 0 100 101 102] 8 10 fmt.Println(s3, len(s3), cap(s3)) // [0 0 0 100 101 102] 6 10 // copy // copy를 위해서 생성한 슬라이스는 기존 슬라이스와 크기가 동일해야 함 lettersCopy1 := make([]string, 0) copy(lettersCopy1, letters) fmt.Println(lettersCopy1) // [] lettersCopy2 := make([]string, len(letters), len(letters)) copy(lettersCopy2, letters) fmt.Println(lettersCopy2) // [a b c d] lettersCopy2[3] = "=" fmt.Println(letters) // [a b c d] fmt.Println(lettersCopy2) // [a b c =] // 삭제, 추출 integers := []int{1, 2, 3, 4, 5} sub1 := integers[1:4] sub2 := integers[2:4] fmt.Println(integers, len(integers), cap(integers)) // [1 2 3 4 5] 5 5 fmt.Println(sub1, len(sub1), cap(sub1)) // [2 3 4] 3 4 fmt.Println(sub2, len(sub2), cap(sub2)) // [3 4] 2 3 // 인덱스로 추출하는 경우 값들이 변결된다. sub1[2] = 100 fmt.Println(integers, len(integers), cap(integers)) // [1 2 3 100 5] 5 5 fmt.Println(sub1, len(sub1), cap(sub1)) // [2 3 100] 3 4 fmt.Println(sub2, len(sub2), cap(sub2)) // [3 100] 2 3 }
 

package main import "fmt" func main() { // 맵 선언 intMap := map[int]string{} intMap[100] = "A" intMap[101] = "B" fmt.Printf("%+v\n", intMap) // map[100:A 101:B] fmt.Println(intMap[100]) // A // make 로 맵 선언 var stringMap = make(map[string]string) stringMap["A"] = "Hello" stringMap["B"] = "World" fmt.Printf("%+v\n", intMap) // map[100:A 101:B] fmt.Println(stringMap["B"]) // World // 선언과 동시에 초기화 tickers := map[string]string{ "GOOG": "Google Inc", "MSFT": "Microsoft", "FB": "FaceBook", } fmt.Printf("%+v\n", tickers) fmt.Println(tickers["FB"]) // 맵에 데이터가 존재 하는지 확인 val, exists := tickers["FB"] fmt.Println(val, exists) // FaceBook true val, exists = tickers["NOT_EXISTS"] fmt.Println(val, exists) // false // range 문으로 key, value 반복 처리 for key, value := range tickers { fmt.Println(key, value) } }
 

패키지

  • main 패키지를 특별하게 인식
    • 실행 시작 점으로 인식
    • 공유 라이브러리를 만들때는 main 으로 만들면 안됨
  • import 키워드로 다른 패키지의 함수를 불러올 수 있음
    • ${GOROOT}/pkg는 표준 패키지
    • ${GOPATH}/pkg는 3rd 파티 패키지
  • 패키지내 함수, 구조체, 인터페이스의 영역
    • 첫문자를 대문자로 시작하면 public
    • 첫문자를 소문자로 시작하면 private
// lib/testlib.go package testlib import "fmt" var pop map[string]string func init() { // 패키지 로드시 map 초기화 pop = make(map[string]string) fmt.Println("init!") } func Hi() { fmt.Println("hi") fmt.Printf("%+v", pop) }
// package.go package main import ( "testlib/lib" ) func main() { testlib.Hi() }
// go.mod module testlib go 1.20

struct

package main import "fmt" // struct 정의 type person struct { name string age int } type dict struct { data map[int]string } //생성자 함수 정의 func newDict() *dict { d := dict{} d.data = map[int]string{} return &d //포인터 전달 } func main() { // person 객체 생성 p := person{} // 필드값 설정 p.name = "Lee" p.age = 10 fmt.Println(p) // 초기화 var p1 person p1 = person{"Bob", 20} p1.name = "Bab" p2 := person{name: "Sean", age: 50} p2.age = 10 // new 를 이용한 초기화 pnew := new(person) pnew.name = "Lee" // p가 포인터라도 . 을 사용한다 // 생성자 함수 dic := newDict() dic.data[1] = "A" }
 

메소드

  • 메소드를 struct의 메소드로 정의할 수 있다.
package main //Rect - struct 정의 type Rect struct { width, height int } //Rect의 area() 메소드 func (r Rect) area() int { r.width++// 실제 값이 변경되지 않는다. 항상 포인터로 받았을 때만 변경된다. return r.width * r.height } // 포인터 Receiver func (r *Rect) area2() int { r.width++ return r.width * r.height } func main() { rect := Rect{10, 20} area1 := rect.area() //메서드 호출 println(rect.width, area1) area2 := rect.area2() //메서드 호출 println(rect.width, area2) // 11 220 출력 }

인터페이스

  • 인터페이스는 메소드의 집합
  • struct는 필드의 집합
 
package main import "math" // Shape 인터페이스 type Shape interface { area() float64 perimeter() float64 } //Rect 정의 type Rect struct { width, height float64 } //Circle 정의 type Circle struct { radius float64 } //Rect 타입에 대한 Shape 인터페이스 구현 func (r Rect) area() float64 { return r.width * r.height } func (r Rect) perimeter() float64 { return 2 * (r.width + r.height) } //Circle 타입에 대한 Shape 인터페이스 구현 func (c Circle) area() float64 { return math.Pi * c.radius * c.radius } func (c Circle) perimeter() float64 { return 2 * math.Pi * c.radius } func showArea(shapes ...Shape) { for _, s := range shapes { a := s.area() //인터페이스 메서드 호출 println(a) } } func main() { r := Rect{10., 20.} c := Circle{10} showArea(r, c) }
 

에러처리

package main import ( "log" "os" ) type error interface { Error() string } type MyError struct { Message string } func (e *MyError) Error() string { return e.Message } func doSomething() error { return &MyError{Message: "my error occured"} } func main() { // 사용자 정의 에러를 잡을 때 myError := doSomething() if myError != nil { println(myError.Error()) } f, err := os.Open("C:\\temp\\1.txt") if err != nil { log.Fatal(err.Error()) } println(f.Name()) }
 

defer, panic, recover

  • defer
    • 함수를 바로 실행하지 않고 종료 시점에 실행
    • defer 문은 후입선출(LIFO) 방식으로 실행
    • try catch finally 문의 finally 처럼 사용
  • panic
    • 실행 시점에서 현재 함수의 defer() 함수를 실행 후 리턴
    • 상위로 계속 리턴하여 에러를 출력하고 종료
  • recover
    • painc() 에 의한 에러를 복구 함
package main import ( "os" "fmt" ) func openFile(fn string) { // defer 함수. panic 호출시 실행됨 defer func() { if r := recover(); r != nil { fmt.Println("OPEN ERROR", r) } }() f, err := os.Open(fn) if err != nil { panic(err) } defer f.Close() } func main() { openFile("Invalid.txt") }

테스트

// go mod module myproject go 1.20
// main.go package main import "fmt" // Add 함수는 두 정수를 더하여 반환합니다. func Add(a, b int) int { return a + b } func main() { fmt.Println("3 + 5 =", Add(3, 5)) }
// main_test.go package main import "testing" // TestAdd는 Add 함수의 동작을 테스트합니다. func TestAdd(t *testing.T) { result := Add(3, 5) expected := 8 if result != expected { t.Errorf("Add(3, 5) = %d; want %d", result, expected) } }

References::

Loading Comments...