# json.Marshal( ) ..? ## Coverage Test ```go= package main import ( "encoding/json" "fmt" ) type temp struct { IntValue int Msg string } func main() { // 1. map to json jsonData, _ := json.Marshal( map[string]interface{}{ "objectValue": map[string]interface{}{ "arrayValue": []int{1, 2}, }, }) fmt.Println(string(jsonData)) // 2. struct to json jsonData, _ = json.Marshal(temp{1, "hello"}) fmt.Println(string(jsonData)) // 3. slice to json jsonData, _ = json.Marshal([]int{1, 2, 3, 4}) fmt.Println(string(jsonData)) // 4. struct array jsonData, _ = json.Marshal( []temp{ {1, "hello"}, {2, "world"}, }) fmt.Println(string(jsonData)) } ``` ```shell= {"objectValue":{"arrayValue":[1,2]}} {"IntValue":1,"Msg":"hello"} [1,2,3,4] [{"IntValue":1,"Msg":"hello"},{"IntValue":2,"Msg":"world"}] ``` - 사용자 정의 구조체도 잘 지원한다. ## Internals --- - Marshal (v any) - reflect.ValueOf(v) -> Value 객체 뽑아서 - 뽑은 Value의 Type()을 호출, 아래 함수에 던져준다. - typeEncoder(t reflect.Type) - newTypeEncoder(t reflect.Type) // 메인 함수 ```go= func newTypeEncoder(t reflect.Type, allowAddr bool) encoderFunc { // If we have a non-pointer value whose type implements // Marshaler with a value receiver, then we're better off taking // the address of the value - otherwise we end up with an // allocation as we cast the value to an interface // 생략 switch t.Kind() { case reflect.Bool: return boolEncoder case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return intEncoder case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: return uintEncoder case reflect.Float32: return float32Encoder case reflect.Float64: return float64Encoder case reflect.String: return stringEncoder case reflect.Interface: return interfaceEncoder case reflect.Struct: return newStructEncoder(t) case reflect.Map: return newMapEncoder(t) case reflect.Slice: return newSliceEncoder(t) case reflect.Array: return newArrayEncoder(t) case reflect.Pointer: return newPtrEncoder(t) default: return unsupportedTypeEncoder } } ``` - 타입 별로 encoder함수를 구현해놓았다. - Value를 해당 타입으로 다시 캐스팅 (4, 12 줄) ```go= func boolEncoder(e *encodeState, v reflect.Value, opts encOpts) { b := e.AvailableBuffer() b = mayAppendQuote(b, opts.quoted) b = strconv.AppendBool(b, v.Bool()) b = mayAppendQuote(b, opts.quoted) e.Write(b) } func intEncoder(e *encodeState, v reflect.Value, opts encOpts) { b := e.AvailableBuffer() b = mayAppendQuote(b, opts.quoted) b = strconv.AppendInt(b, v.Int(), 10) b = mayAppendQuote(b, opts.quoted) e.Write(b) } ``` - 중요한건 구조체와 배열을 어떻게 처리하는가 ```go= func newArrayEncoder(t reflect.Type) encoderFunc { enc := arrayEncoder{typeEncoder(t.Elem())} return enc.encode } ``` - array같은 경우 t.Elem()을 통해 요소의 인코더를 재귀적으로 뽑아냄 - slice도 비슷하게 - 구조체 - 구조체 reflect.Struct로 판단 - func typeFields(t reflect.Type) structFields - 요소 돌면서 타입 체크, ```go= // A StructField describes a single field in a struct. type StructField struct { // Name is the field name. Name string // PkgPath is the package path that qualifies a lower case (unexported) // field name. It is empty for upper case (exported) field names. // See https://golang.org/ref/spec#Uniqueness_of_identifiers PkgPath string Type Type // field type Tag StructTag // field tag string Offset uintptr // offset within struct, in bytes Index []int // index sequence for Type.FieldByIndex Anonymous bool // is an embedded field } ``` - [ ] 임베디드 필드...