MST

星途 面试题库

面试题:Go反射在通用数据处理函数中的应用

假设你要编写一个通用的函数,它接收一个空接口类型的参数,该参数可能是任意类型的结构体。函数需要遍历结构体的所有可导出字段,并根据字段的标签(tag)对字段进行不同的处理,比如某些字段进行加密处理,某些字段进行日志记录。请用Go语言基于反射实现这个通用函数,并说明实现思路。
26.3万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

实现思路

  1. 使用 reflect.ValueOf 获取传入接口值的 reflect.Value
  2. 使用 reflect.TypeOf 获取传入接口值的 reflect.Type
  3. 检查 reflect.Value 是否是结构体类型,如果不是则返回错误。
  4. 遍历结构体的字段,通过 reflect.Type.Field 获取每个字段的信息,包括标签。
  5. 根据标签判断对字段进行何种处理,例如加密或日志记录。
  6. 对于需要修改的字段值,通过 reflect.Value 的方法进行操作。

代码实现

package main

import (
	"fmt"
	"reflect"
)

// 模拟加密函数
func encrypt(str string) string {
	return "encrypted_" + str
}

// 模拟日志记录函数
func logInfo(str string) {
	fmt.Printf("Logging: %s\n", str)
}

func processStruct(data interface{}) error {
	valueOf := reflect.ValueOf(data)
	typeOf := reflect.TypeOf(data)

	// 检查是否为指针类型,如果是则获取指针指向的值
	if valueOf.Kind() == reflect.Ptr {
		valueOf = valueOf.Elem()
		typeOf = typeOf.Elem()
	}

	// 检查是否为结构体类型
	if typeOf.Kind() != reflect.Struct {
		return fmt.Errorf("input is not a struct")
	}

	for i := 0; i < typeOf.NumField(); i++ {
		field := typeOf.Field(i)
		tag := field.Tag.Get("process")

		switch tag {
		case "encrypt":
			if valueOf.Field(i).Kind() == reflect.String {
				original := valueOf.Field(i).String()
				encrypted := encrypt(original)
				valueOf.Field(i).SetString(encrypted)
			}
		case "log":
			if valueOf.Field(i).Kind() == reflect.String {
				logInfo(valueOf.Field(i).String())
			}
		}
	}

	return nil
}

你可以这样调用这个函数:

type TestStruct struct {
	Name string `process:"encrypt"`
	Info string `process:"log"`
}

func main() {
	test := TestStruct{
		Name: "John",
		Info: "Some information",
	}

	err := processStruct(&test)
	if err != nil {
		fmt.Println(err)
	}

	fmt.Println(test)
}