MST

星途 面试题库

面试题:Go json解析自定义错误处理机制设计

在Go语言的encoding/json包基础上,设计一个自定义的错误处理机制,要求能够区分不同类型的解析错误(如格式错误、类型不匹配、缺少必要字段等),并通过自定义的错误接口提供详细的错误上下文信息,包括JSON数据的路径信息。请给出完整的代码设计和使用示例。
18.0万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试
package main

import (
    "encoding/json"
    "fmt"
)

// 自定义错误类型
type JSONParseError struct {
    ErrType   string
    Context   string
    Path      string
}

func (e *JSONParseError) Error() string {
    return fmt.Sprintf("%s: %s at path %s", e.ErrType, e.Context, e.Path)
}

// 自定义错误接口
type JSONError interface {
    Error() string
    GetErrType() string
    GetContext() string
    GetPath() string
}

func (e *JSONParseError) GetErrType() string {
    return e.ErrType
}

func (e *JSONParseError) GetContext() string {
    return e.Context
}

func (e *JSONParseError) GetPath() string {
    return e.Path
}

// 自定义解析函数
func CustomUnmarshal(data []byte, v interface{}) error {
    var pathStack []string
    decoder := json.NewDecoder(&jsonReader{data: data})
    decoder.UseNumber()
    var err error
    err = decoder.Decode(v)
    if err != nil {
        var parseErr *JSONParseError
        if syntaxErr, ok := err.(*json.SyntaxError); ok {
            parseErr = &JSONParseError{
                ErrType:   "SyntaxError",
                Context:   fmt.Sprintf("invalid character %q at position %d", syntaxErr.Error()[10], syntaxErr.Offset),
                Path:      buildPath(pathStack),
            }
        } else if unmarshalTypeErr, ok := err.(*json.UnmarshalTypeError); ok {
            parseErr = &JSONParseError{
                ErrType:   "UnmarshalTypeError",
                Context:   fmt.Sprintf("found type %s, expected %s", unmarshalTypeErr.Value, unmarshalTypeErr.Type),
                Path:      buildPath(pathStack),
            }
        } else if unexpectedEndErr, ok := err.(*json.UnexpectedEndError); ok {
            parseErr = &JSONParseError{
                ErrType:   "UnexpectedEOFError",
                Context:   fmt.Sprintf("unexpected end of JSON input at position %d", unexpectedEndErr.Offset),
                Path:      buildPath(pathStack),
            }
        } else {
            parseErr = &JSONParseError{
                ErrType:   "UnknownError",
                Context:   err.Error(),
                Path:      buildPath(pathStack),
            }
        }
        return parseErr
    }
    return nil
}

func buildPath(pathStack []string) string {
    if len(pathStack) == 0 {
        return ""
    }
    var path string
    for _, p := range pathStack {
        path += "/" + p
    }
    return path
}

type jsonReader struct {
    data []byte
    pos  int
}

func (jr *jsonReader) Read(p []byte) (n int, err error) {
    if jr.pos >= len(jr.data) {
        return 0, nil
    }
    n = copy(p, jr.data[jr.pos:])
    jr.pos += n
    return n, nil
}

// 使用示例
func main() {
    type Person struct {
        Name string `json:"name"`
        Age  int    `json:"age"`
    }
    jsonData := []byte(`{"name":"John", "age":"twenty"}`)
    var person Person
    err := CustomUnmarshal(jsonData, &person)
    if err != nil {
        if jsonErr, ok := err.(JSONError); ok {
            fmt.Printf("Error Type: %s\n", jsonErr.GetErrType())
            fmt.Printf("Context: %s\n", jsonErr.GetContext())
            fmt.Printf("Path: %s\n", jsonErr.GetPath())
        } else {
            fmt.Println("Unexpected error:", err)
        }
    } else {
        fmt.Println("Successfully unmarshaled:", person)
    }
}
  1. 自定义错误类型与接口:定义了JSONParseError结构体来存储错误类型、上下文和路径信息,并实现了JSONError接口,包含获取这些信息的方法。
  2. 自定义解析函数CustomUnmarshal函数使用json.NewDecoder进行解码,并在发生错误时,根据错误类型构造自定义的JSONParseError
  3. 路径构建buildPath函数用于构建JSON数据的路径。
  4. 使用示例:在main函数中,定义了一个简单的结构体Person,并尝试解析包含类型不匹配的JSON数据,展示如何处理和输出自定义错误。