我可以使用typedef进行类型断言吗?
我有一个自定义类型,可以让我更方便地使用 API:
type Object map[string]interface{}
这件事不起作用:
var mockResponse = map[string]interface{}{"success": true}
resp, ok := mockResponse.(Object)
// ok = false
我可以做任何事情,这样mockResponse.(Object)的ok是true?基本上都是一样的类型。。。
回答
首先,您的“伪代码”是编译时错误。您不能对具有具体类型的值使用类型断言(没有意义,具体类型是具体类型,没有别的),您只能在接口值上使用它。
例子应该是:
var mockResponse interface{} = map[string]interface{}{"success": true}
resp, ok := mockResponse.(Object)
请注意,如果mockResponse是 type map[string]interface{},则不需要类型断言,您可以简单地将其转换为Object:
var mockResponse = map[string]interface{}{"success": true}
obj := Object(mockResponse)
该类型定义创建了一个新的,独特的类型。并且仅当您使用相同的具体类型时,对具体类型的类型断言才成立。
您可以做的是编写一个Object从接口值中提取的辅助函数,该函数可以处理这两种情况map[string]interface{},也可以处理具体类型Object:
func getObj(x interface{}) (o Object, ok bool) {
switch v := x.(type) {
case Object:
return v, true
case map[string]interface{}:
return Object(v), true
}
return nil, false
}
测试它:
resp, ok := getObj(map[string]interface{}{"success": true})
fmt.Println(resp, ok)
resp, ok = getObj(Object{"success": true})
fmt.Println(resp, ok)
resp, ok = getObj("invalid")
fmt.Println(resp, ok)
输出(在Go Playground上试试):
map[success:true] true
map[success:true] true
map[] false
注意:上面getObj()没有处理可以Object从接口值“获取” an 的所有可能情况。
例如,如果我们有这样的类型定义:
type Object2 Object
Passing a value of Object2 to getObj(), an Object would not be extracted from it, even though a value of type Object2 could be converted to Object:
resp, ok = getObj(Object2{"success": true})
fmt.Println(resp, ok) // map[] false
If you want to handle all possible cases where the concrete value is convertible to Object, you may use reflection:
var objType = reflect.TypeOf(Object{})
func getObj(x interface{}) (o Object, ok bool) {
if v := reflect.ValueOf(x); v.Type().ConvertibleTo(objType) {
o, ok = v.Convert(objType).Interface().(Object)
return
}
return nil, false
}
Testing it (try this one on the Go Playground):
resp, ok = getObj(Object2{"success": true})
fmt.Println(resp, ok) // map[success:true] true
Using reflection is slower than a simple type assertion or type switch, so you can mix the 2 solutions:
func getObj(x interface{}) (o Object, ok bool) {
// First try the trivial cases:
switch v := x.(type) {
case Object:
return v, true
case map[string]interface{}:
return Object(v), true
}
// Then revert to reflection:
if v := reflect.ValueOf(x); v.Type().ConvertibleTo(objType) {
o, ok = v.Convert(objType).Interface().(Object)
return
}
return nil, false
}