英文:
Checking for compatible types using reflection in Go
问题
尽管我知道在Go语言中恐慌可能不是惯用的做法,但我想测试一下,以确保在某些条件下函数会引发恐慌,而在其他条件下不会引发恐慌。
以下是一个函数的示例:
func PanicOnErr(potentialErr error) {
if potentialErr != nil {
panic(potentialErr)
}
}
以下是用于检查函数是否会引发恐慌的实现:
func InvocationCausedPanic(f interface{}, params ...interface{}) bool {
// 获取函数的签名。
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)
然而,似乎可以使用nil
和通过调用errors.New
生成的内容(似乎是*errors.errorString
类型)来调用PanicOnErr
。
因此,是否有一种方法可以检查某个参数的类型是否适合调用某个函数?
虽然我知道可以使用defer
和recover
更简单地测试函数,但我想知道是否有可能编写一个通用函数,可以接受任何函数和参数,并确定它是否导致了恐慌(假设函数完成)。
相关的Go Playground:
http://play.golang.org/p/qUG7OGuIbD
英文:
Although I am aware that it might not be idiomatic to panic in Go, I would like to test to ensure a function panics under certain conditions and not in others.
An example of the function.
func PanicOnErr(potentialErr error) {
if potentialErr != nil {
panic(potentialErr)
}
}
The following is an implementation for checking if the function will 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
}
Calling either of the following will cause the type-check to fail.
InvocationCausedPanic(PanicOnErr, errors.New("Some error."))
InvocationCausedPanic(PanicOnErr, nil)
However, it seems possible to call PanicOnErr
using both nil
and something generate by calling errors.New
(seems to be of type *errors.errorString
).
As such, is there a way to check if the type of some parameter is suitable for invoking some function?
While I know it is possible to use defer and recover to more simply test the function, I am curious as to whether it is possible to write a general function that can accept any function and parameters and determine whether it resulted in a panic (assuming the function completes).
Relevant Go Playground:
http://play.golang.org/p/qUG7OGuIbD
答案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)
}
英文:
Use this function to determine if the parameter is compatible:
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)
}
<kbd>playground</kbd>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论