
길이 고정되어 있고, 인덱스 통해 접근
var strArray1 [5]string
strArray1[0] = "a"
...
strArray1[4] = "e"
fmt.Println(strArray1)
//문제1 : 0~4까지 모두 채운후, 전체 코드와 해당 출력 결과는?
var strArray2 xxxx = xxxx {"1", "2", "3", "4", "5"}
fmt.Println(strArray2)
//문제2 : xxxx 자리에 올바른 배열을 선언하고 전체 코드와 해당 출력 결과는?
strArray3 := [5]string{"10", "20", "30"}
fmt.Println(strArray3)
//문제3 : 전체 코드와 해당 출력 결과는?
strArray4 := [...]string{"100", "200", "300"}
fmt.Println(strArray4)
fmt.Println(len(strArray4))
//문제4 : 전체 코드와 두 출력 결과는?
strArray5 := [5]string{2:"codz", 4:"states"}
fmt.Println(strArray5)
fmt.Printf("%#v\n", strArray5)
//문제5 : 전체 코드와 해당 출력 결과는?
길이가 동적으로 늘어나는 배열
실제 자료형의 타입은 레퍼런스 타입
레퍼런스 타입 : 객체의 참조를 저장 (밸류가 아니라)
메모리 효율 좋고, 값 변경 가능
var a1 []int
var a2 [5]int
fmt.Println(reflect.ValueOf(a1).Kind())
fmt.Println(reflect.TypeOf(a1))
fmt.Println(reflect.ValueOf(a2).Kind())
fmt.Println(reflect.TypeOf(a2))
//a : 출력의 결과값은?
var intSlice = []int{0, 1, 2, 3}
fmt.Printf("%#v\n", intSlice)
fmt.Printf("%v\n", intSlice)
fmt.Printf(":2 %v\n", intSlice[:2])
fmt.Printf("1:3 %v\n", intSlice[1:3])
fmt.Printf("2: %v\n", intSlice[2:])
fmt.Printf("0:3 %v\n", intSlice[0:3])
//b : 각 출력 결과값은?
key-value 형으로 데이터 저장
자료형 타입 : 레퍼런스
key의 자료형은 모든 데이터 타입을 사용 가능
선언 : var 맵명 [키 자료형]값 자료형
var map1 map[string]int
map2 := make(map[string]string)
map3 := make(map[int]string, 1000)
var timeZone = map[string]int{
"UTC": 0,
"EST": 5,
"CST": 6,
"MST": 7,
"PST": 8,
}
timeSet := timeZone["CST"]
//a : timeZone관련, 루프를 돌면서 key-value 형태로 출력하는 코드 작성
attend := map[string]bool{
"codz": true,
"status": false,
"alice": true,
... //이하 생략
}
다른 언어들과 마찬가지로, 여러 변수 타입을 담아 하나의 형태로 만들 때 사용
type Persons struct {
Name string
Age int
Pnum string
}
var pers Persons
pers.Name = "codz"
pers.Age = 23
pers.Pnum = "01098765432"
// new 사용
p1 := new(Persons)
p1.Name = "codz"
p1.Age = 29
p1.Pnum = "01098765432"
fmt.Println("Person 1 : ", p1)
fmt.Printf("%#v\n", p1)
var p2 = new(Persons)
p2.Name = "states"
p2.Age = 33
p2.Pnum = "01054329876"
fmt.Println("Person 2 : ", p2)
fmt.Printf("%#v\n", p2)
//선언과 동시에 초기화
var p3 = &Persons{"test", 17, "01045673210"}
fmt.Println("Person 3 : ", p3)
fmt.Printf("%#v\n", p3)
//구조체 배열 형식
p4 := []Persons{
{
Name: "p1",
Age: 10,
Pnum: "9876",
},
{
Name: "p2",
Age: 9,
Pnum: "8765",
},
}
fmt.Println(p4)
fmt.Printf("%#v\n", p4)
메서드의 집합 (구조체는 필드의 집합)
객체 행위를 지정해주는 방법
type Persons interface {
Student() int
Player() string
}
//예제1 : 인터페이스 데이터 선언
var x interface{}
x = 1
fmt.Println(x)
x = "Hello World"
fmt.Println(x)
//예제2 : 인터페이스 데이터 타입 변환과 반환값
var x interface{}
x = "10"
sVal := x.(string)
fmt.Println(sVal)
x = 10
nVal, bCnv := x.(int)
fmt.Println(nVal, bCnv)
//예제3 : 타입에 따른 핸들링 기법
var x interface{}
x = "hello"
xType := reflect.TypeOf(x)
if xType.Kind() == reflect.Int {
fmt.Println("Int ", x)
} else if xType.Kind() == reflect.String {
fmt.Println("string ", x)
}
//예제4 : 구조체를 선언하고, 구조체별 인터페이스 핸들링
codz := Persons{Name: "codz", Age: 20}
var x interface{}
x = codz
xPerson := x.(Persons)
xPrsAge := x.(Persons).Age
ty := reflect.TypeOf(xPerson)
fmt.Printf("%v, %d, %s\n", xPerson, xPrsAge, xPerson.Name)
fmt.Println(ty.String())
new()는 메모리를 할당하는 내장함수.
type File struct{
fd int
name string
dirinfo string
nepipe int
}
// 생성자 필요
func NewFile(fd int, name string) *File {
if fd < 0 {
return nil
}
f := new(File) //생성자
f.fd = fd //초기화
f.name = name //
f.dirinfo = nil //
f.nepipe = 0 //
return f //포인터 리턴
}
// 복합 레터럴 사용하여 간소화
func NewFile(fd int, name string) *File {
if fd < 0 {
return nil
}
f := File{fd, name, nil, 0} //복합리터럴 사용
return &f
}
func NewFile(fd int, name string) *File {
if fd < 0 {
return nil
}
return &File{fd, name, nil, 0} //복합리터럴 사용
}
func NewFile(fd int, name string) *File {
if fd < 0 {
return nil
}
return &File{fd: fd, name: name} //복합리터럴 사용
}
new()와 달리 특정 데이터 타입에서는 미리 사용할 준비가 될 수 있게 초기화 해줘야 하는 경우 존재
var p *[]int = new([]int) // slice 구조체를 할당한다; *p == nil; 유용하지 않음
var v []int = make([]int, 100) // slice v는 이제 100개의 int를 갖는 배열을 참조
// 불필요하게 복잡한 경우:
var p *[]int = new([]int)
*p = make([]int, 100, 100)
// 추천 형태
v := make([]int, 100)
i := 1
for ; i <= 10; i++ {
fmt.Println(i)
}
i = 1
for i <= 10 {
fmt.Println(i)
i++
}
for i := 1; ; i++ {
fmt.Println(i)
if i == 10 {
break
}
}
for i := 0; i < 100; i++ {
fmt.Printf("%d", i)
}
var arr [10]int
// 배열이기 때문에 return의 첫번째 값이 index이다.
for idx0, _ := range arr {
arr[idx0] = len(arr) - idx0
}
for idx1, value1 := range arr {
fmt.Println("idx: ", idx1, "value: ", value1)
}
func getValue(value int) (int) {
return value
}
func main() {
x := getValue(10) // 출력: x == 10
y := 20 // 출력: y == 20
switch x {
case 10:
fmt.Println("x == 10")
// golang은 컴파일러가 case문마다 자동으로 break문을 추가해준다.
case 20:
fmt.Println("x == 20")
}
switch y {
case 10:
fmt.Println("y == 10")
case 20:
fmt.Println("y == 20")
}
}
error 타입을 사용해서 다룰 수 있게 했다.
func divide(a, b int) (n int, err error) {
if b == 0 {
return 0, errors.New("분모가 0이면 안됩니다.")
}
return a / b, nil
}
func main() {
res, err := divide(4, 2) // 코드를 사용하는 쪽에서 에러를 다룸
if err != nil {
fmt.Println("ERROR : ", err.Error())
} else {
fmt.Println(res)
}
}
패닉 : 에러로 인해 프로세스가 강제로 종료되는 상황
직접 panic 함수로 발생시킬 수 있음
if repo, err != model.New(conf) ; err != nil {
panic(err)
} else if ctl, err != control.New(conf, repo); err!=nil {
panic(err)
}
package main
import (
"errors"
"fmt"
)
var res = 1
func Calc(n int) {
if n == 0 {
panic(errors.New("zero calc"))
} else {
res *= n
fmt.Println("Result: ", res)
}
}
func main() {
Calc(1)
Calc(2)
Calc(0)
Calc(3)
}
패닉 발생 이후 구문은 실행되지 않음, 패닉이 발생해도 회복 위해 recover 사용
일반적으로 고루틴 스택 해제를 시작하여, 지연된 함수를 실행할 때 이용, 이로써 고루틴 제어를 다시 얻고 정상적인 실행 재개
func server(workChan *Work) {
for i=0;i <= 10; i++ {
go safeDo(work)
}
}
func safeDo(work *Work) {
defer func() { // 종료 및 실패된 work만 리커버
if err := recover(); err!= nil {
log.Println("work failed: ", err)
}
}()
do(work) //work 실행
}
기본적으로 테스트 프레임워크 내장
controller.go
package controller
import ( "fmt" )
func Sum(a, b int) int {
fmt.Println("Sum : ", a, " + ", b)
return a + b
}
main.go
package main
import ( "fmt" )
func main() {
fmt.Println("Hello World")
}
go_test.go
package go_test
import (
"fmt"
clt "lecture/go-testing/controller" // user package import
"testing"
)
func TestCalc(t *testing.T) {
fmt.Println("Hello world!")
ressum := clt.Sum(1, 2)
t.Errorf("sum = %d", ressum)
if ressum == 3 {
t.Error("fail calc")
}
}
테스트 실행
go mod init
go mod tidy
go test go_test.go
vscode 내장 디버그 기능이 편하고 유용함
main.go에서만 디버깅 시작해야