MST

星途 面试题库

面试题:Go反射在函数调用中的应用

假设你有一个函数,其参数和返回值类型在运行时才能确定,使用Go反射实现对这个函数的动态调用,要求处理不同数量和类型的参数,同时考虑错误处理,写出完整代码。
28.5万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试
package main

import (
    "fmt"
    "reflect"
)

func CallFunction(f interface{}, args ...interface{}) (results []interface{}, err error) {
    // 获取函数的反射值
    funcValue := reflect.ValueOf(f)
    if funcValue.Kind() != reflect.Func {
        return nil, fmt.Errorf("input is not a function")
    }

    // 检查参数数量
    if len(args) != funcValue.Type().NumIn() {
        return nil, fmt.Errorf("number of arguments does not match")
    }

    // 准备参数的反射值
    var argValues []reflect.Value
    for i, arg := range args {
        argValue := reflect.ValueOf(arg)
        if argValue.Type() != funcValue.Type().In(i) {
            return nil, fmt.Errorf("argument %d type does not match", i)
        }
        argValues = append(argValues, argValue)
    }

    // 调用函数
    resultsValues := funcValue.Call(argValues)

    // 处理返回值
    for _, resultValue := range resultsValues {
        results = append(results, resultValue.Interface())
    }

    return results, nil
}

// 示例函数1:接受两个整数并返回它们的和
func Add(a, b int) int {
    return a + b
}

// 示例函数2:接受一个字符串并返回其长度
func StringLength(s string) int {
    return len(s)
}

func main() {
    // 调用Add函数
    result, err := CallFunction(Add, 3, 5)
    if err != nil {
        fmt.Println("Error:", err)
    } else {
        fmt.Println("Add result:", result[0])
    }

    // 调用StringLength函数
    result, err = CallFunction(StringLength, "hello")
    if err != nil {
        fmt.Println("Error:", err)
    } else {
        fmt.Println("StringLength result:", result[0])
    }
}

上述代码中:

  1. CallFunction 函数接受一个接口类型的函数 f 以及可变数量的接口类型参数 args
  2. 使用 reflect.ValueOf 获取函数的反射值,并检查其是否为函数类型。
  3. 检查传入的参数数量是否与函数期望的参数数量一致。
  4. 遍历传入的参数,检查每个参数的类型是否与函数期望的参数类型一致。
  5. 使用 funcValue.Call 调用函数,并获取返回值。
  6. 将返回值的反射值转换为接口类型,并添加到结果切片中。
  7. main 函数中,通过 CallFunction 调用了两个不同的示例函数 AddStringLength,展示了如何动态调用不同参数和返回值类型的函数,并处理可能的错误。