# 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
}
```
- [ ] 임베디드 필드...