似乎我错过了一些重要的东西,但我无法弄清楚它是什么。我使用reflect通过接口访问嵌入式字段。我遇到的问题是根据runtime/pprof
,它占用了大量的CPU。我不喜欢在所有车辆上实施Setter和Getter方法,那么有更好的方法吗?
简化样本:
package main
import(
"reflect"
"fmt"
)
// the "contract" is that all vehicles have an embedded Engine
type Vehicle interface {}
type Engine struct {
Power float64
Cubic float64
}
type Car struct {
Engine
Weight float64
TopSpeed float64
}
// more Vehicles with Engines here...
func EngineCheck(v Vehicle) {
// this does not work:
//power := v.Power
// reflection works but eats up a lot of CPU:
power := reflect.ValueOf(v).Elem().FieldByName("Power").Interface().(float64)
fmt.Println(power)
}
func main() {
c1 := &Car{Engine{120.0, 1.2}, 1.5, 250}
EngineCheck(c1)
}
答案 0 :(得分:2)
如果您知道快速的确切类型,则可以使用type assertion,如果失败则只返回反射。
例如:
func EngineCheck(v Vehicle) {
var power float64
if eng, ok := v.(*Car); ok {
power = eng.Power
} else {
power = reflect.ValueOf(v).Elem().FieldByName("Power").Interface().(float64)
}
fmt.Println(power)
}
请注意,Car
和*Car
类型不同,上面的示例只会跳过"跳过"如果您传递的值确实是指针,则为反射部分:*Car
。
如果有多种可能的"可接受的"类型,您可以使用type switch。例如,如果您传递Car
或*Car
,则可以从两者中获取Power
值。此外,如果传递Engine
或*Engine
,则同样适用。
func EngineCheck(v Vehicle) {
var power float64
switch i := v.(type) {
case *Car:
power = i.Power
case Car:
power = i.Power
case *Engine:
power = i.Power
case Engine:
power = i.Power
default:
power = reflect.ValueOf(v).Elem().FieldByName("Power").Interface().(float64)
}
fmt.Println(power)
}
但惯用解决方案仍然是向Vehicle
添加一个getter函数:
type Vehicle interface {
GetPower() float64
}
请注意,您无需在任何地方实施GetPower()
。如果您在Engine
:
func (e Engine) GetPower() float64 {
return e.Power
}
您将Engine
嵌入Car
(正如您所做的那样),您的Car
类型会在其method set中自动拥有此GetPower()
方法(已提升)因此它会自动实现Vehicle
。然后你的EngineCheck()
函数就像这样简单:
func EngineCheck(v Vehicle) {
fmt.Println(v.GetPower())
}
在Go Playground上尝试所有这三种变体。