Golang中如何创建可接受任意类型的结构体

Golang中如何创建可接受任意类型的结构体 大家好,

我想让从 database.go 中的函数返回的 Response 能够自定义。

例如,在领域层文件中,我有这个函数: UserLogin(userCredential Credentials, password string) (*Response, error)

我希望这个函数的响应返回一个 token: "user-generated-token"

而在另一个函数中,我希望返回类似这样的消息作为响应: RegisterUser(input User) (*Response, error) message: "User created"

在另一个从数据库函数返回的函数中,返回一个 JSON 对象或 JSON 数组。 然后将来自 database.go 的响应放入这个函数的 payload 参数部分:

func RespondJSON(w http.ResponseWriter, status int, result bool, message string, payload interface{}) {
	response, err := json.Marshal(&domain.BaseEndPoint{
		Success:   result,
		Message:  message,
		Response: payload,
	})
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		w.Write([]byte(err.Error()))
		return
	}
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(status)
	w.Write([]byte(response))
}

为每个响应都创建一个结构体是不合理的。我该如何创建一个能够接受任何类型和键值对的结构体?这是我目前的结构体:

type Response struct {
Result interface{} `json:"result"`
}

在 Postman 中的结果:

     "success": true,
    "message ": "welcome .....",
    "response": {
        "result": {
            "mobile": "+1 123456",
            "password": "123456"
        }
    }
}

我需要一种方法,在这种情况下只移除 result,这样一切就都正常了。

附注:在领域层中为结果使用以下类型是否可以?

[]map[string]string

但我想当我需要返回产品列表或用户列表时会遇到问题。[]map 可能不适用。这样对吗?

或者我们可能根本不需要一个名为 Response 的结构体?而只是在领域层中创建我们需要的返回类型?


更多关于Golang中如何创建可接受任意类型的结构体的实战教程也可以访问 https://www.itying.com/category-94-b0.html

3 回复

你能澄清一下你在问什么吗?

更多关于Golang中如何创建可接受任意类型的结构体的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


我不完全确定你的问题。但是,你可以直接使用一个空接口,而不是使用一个内部包含空接口的结构体。

var Response interface{}

你可以使用它来代替:

type Response struct {
Result interface{} `json:"result"`
}

希望这能解答你的问题。

在Golang中创建可接受任意类型的结构体,通常使用interface{}any类型。从你的代码看,你已经接近解决方案了,只需要调整结构体设计。

解决方案

1. 使用泛型结构体(推荐Go 1.18+)

// 通用响应结构体
type Response[T any] struct {
    Success bool   `json:"success"`
    Message string `json:"message"`
    Data    T      `json:"data,omitempty"`
}

// 使用示例
func UserLogin(userCredential Credentials, password string) (*Response[string], error) {
    token := "user-generated-token"
    return &Response[string]{
        Success: true,
        Message: "Login successful",
        Data:    token,
    }, nil
}

func RegisterUser(input User) (*Response[string], error) {
    return &Response[string]{
        Success: true,
        Message: "User created",
        Data:    "",
    }, nil
}

func GetUsers() (*Response[[]User], error) {
    users := []User{
        {ID: 1, Name: "John"},
        {ID: 2, Name: "Jane"},
    }
    return &Response[[]User]{
        Success: true,
        Message: "Users retrieved",
        Data:    users,
    }, nil
}

2. 使用interface{}类型

type Response struct {
    Success bool        `json:"success"`
    Message string      `json:"message"`
    Data    interface{} `json:"data,omitempty"`
}

// 使用示例
func UserLogin(userCredential Credentials, password string) (*Response, error) {
    token := "user-generated-token"
    return &Response{
        Success: true,
        Message: "Login successful",
        Data:    token,
    }, nil
}

func GetProducts() (*Response, error) {
    products := []Product{
        {ID: 1, Name: "Product A"},
        {ID: 2, Name: "Product B"},
    }
    return &Response{
        Success: true,
        Message: "Products retrieved",
        Data:    products,
    }, nil
}

3. 针对你的具体问题

修改你的RespondJSON函数:

func RespondJSON(w http.ResponseWriter, status int, success bool, message string, data interface{}) {
    response := map[string]interface{}{
        "success": success,
        "message": message,
    }
    
    if data != nil {
        response["response"] = data
    }
    
    jsonResponse, err := json.Marshal(response)
    if err != nil {
        w.WriteHeader(http.StatusInternalServerError)
        w.Write([]byte(err.Error()))
        return
    }
    
    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(status)
    w.Write(jsonResponse)
}

// 使用示例
func handleLogin(w http.ResponseWriter, r *http.Request) {
    // ... 处理逻辑
    token := map[string]string{
        "token": "user-generated-token",
    }
    RespondJSON(w, http.StatusOK, true, "Login successful", token)
}

func handleUsers(w http.ResponseWriter, r *http.Request) {
    // ... 处理逻辑
    users := []User{
        {ID: 1, Name: "John", Email: "john@example.com"},
        {ID: 2, Name: "Jane", Email: "jane@example.com"},
    }
    RespondJSON(w, http.StatusOK, true, "Users retrieved", users)
}

4. 关于[]map[string]string的问题

// 不推荐使用 []map[string]string,因为:
// 1. 类型不安全
// 2. 性能较差
// 3. 难以维护

// 推荐使用具体类型
type User struct {
    ID       int    `json:"id"`
    Name     string `json:"name"`
    Email    string `json:"email"`
    Mobile   string `json:"mobile,omitempty"`
}

type Product struct {
    ID    int     `json:"id"`
    Name  string  `json:"name"`
    Price float64 `json:"price"`
}

// 这样可以直接返回
func GetUsers() ([]User, error) {
    // ... 数据库查询
    return users, nil
}

5. 完整示例

package main

import (
    "encoding/json"
    "net/http"
)

// 领域层结构体
type User struct {
    ID       int    `json:"id"`
    Name     string `json:"name"`
    Email    string `json:"email"`
}

type LoginResponse struct {
    Token string `json:"token"`
    ExpiresIn int `json:"expires_in"`
}

// 通用响应包装器
type ApiResponse struct {
    Success bool        `json:"success"`
    Message string      `json:"message"`
    Data    interface{} `json:"data,omitempty"`
}

// 领域层函数
func UserLogin(credentials Credentials) (*ApiResponse, error) {
    // ... 验证逻辑
    loginData := LoginResponse{
        Token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9",
        ExpiresIn: 3600,
    }
    
    return &ApiResponse{
        Success: true,
        Message: "Login successful",
        Data:    loginData,
    }, nil
}

func GetUserList() (*ApiResponse, error) {
    users := []User{
        {ID: 1, Name: "John Doe", Email: "john@example.com"},
        {ID: 2, Name: "Jane Smith", Email: "jane@example.com"},
    }
    
    return &ApiResponse{
        Success: true,
        Message: "Users retrieved successfully",
        Data:    users,
    }, nil
}

// HTTP处理器
func loginHandler(w http.ResponseWriter, r *http.Request) {
    response, err := UserLogin(credentials)
    if err != nil {
        // 错误处理
        errorResponse := ApiResponse{
            Success: false,
            Message: err.Error(),
        }
        json.NewEncoder(w).Encode(errorResponse)
        return
    }
    
    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(response)
}

这样设计可以:

  1. 移除多余的result包装层
  2. 保持类型安全
  3. 支持任意类型的响应数据
  4. 提供一致的API响应格式
回到顶部