在 Go 中使用反射检查兼容类型

虽然我知道在 Go 中恐慌可能不是惯用的,但我想测试以确保函数在某些条件下而不是在其他条件下发生恐慌。


函数的一个例子。


func PanicOnErr(potentialErr error) {

    if potentialErr != nil {

        panic(potentialErr)

    }

}

以下是检查函数是否会 panic 的实现。


func InvocationCausedPanic(f interface{}, params ...interface{}) bool {

    // Obtain the function's signature.

    reflectedFunc := reflect.ValueOf(f)

    funcType := reflect.TypeOf(f)


    if funcType.NumIn() != len(params) {

        panic("InvocationCausedPanic called with a function and an incorrect number of parameter(s).")

    }


    reflectedParams := make([]reflect.Value, len(params))

    for paramIndex, paramValue := range params {

        expectedType := funcType.In(paramIndex)

        actualType := reflect.TypeOf(paramValue)


        if actualType != expectedType {

            errStr := fmt.Sprintf("InvocationCausedPanic called with a mismatched parameter type [parameter #%v: expected %v; got %v].", paramIndex, expectedType, actualType)

            panic(errStr)

        }


        reflectedParams[paramIndex] = reflect.ValueOf(paramValue)

    }


    return invoke(reflectedFunc, reflectedParams)

}


func invoke(reflectedFunc reflect.Value, reflectedParams []reflect.Value) (panicked bool) {

    defer func() {

        if r := recover(); r != nil {

            panicked = true

        }

    }()


    reflectedFunc.Call(reflectedParams)

    return

}

调用以下任一方法都会导致类型检查失败。


InvocationCausedPanic(PanicOnErr, errors.New("Some error."))

InvocationCausedPanic(PanicOnErr, nil)

但是,似乎可以PanicOnErr使用两者进行调用,nil并且可以通过调用生成某些内容errors.New(似乎是 类型*errors.errorString)。


因此,有没有办法检查某个参数的类型是否适合调用某个函数?


虽然我知道可以使用 defer 和 recovery 来更简单地测试函数,但我很好奇是否可以编写一个通用函数来接受任何函数和参数并确定它是否导致了恐慌(假设功能完成)。


慕妹3146593
浏览 159回答 1
1回答

胡子哥哥

使用此函数确定参数是否兼容:func compatible(actual, expected reflect.Type) bool {  if actual == nil {    k := expected.Kind()    return k == reflect.Chan ||            k == reflect.Func ||            k == reflect.Interface ||            k == reflect.Map ||            k == reflect.Ptr ||            k == reflect.Slice  }  return actual.AssignableTo(expected)}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go