Reflection 通过接口访问嵌入式类型字段
我似乎错过了一些重要的事情,但我不知道是什么。我使用reflect通过接口访问嵌入式类型字段。我遇到的问题是,根据Reflection 通过接口访问嵌入式类型字段,reflection,go,struct,interface,embedding,Reflection,Go,Struct,Interface,Embedding,我似乎错过了一些重要的事情,但我不知道是什么。我使用reflect通过接口访问嵌入式类型字段。我遇到的问题是,根据运行时/pprof它会占用大量CPU。我不喜欢在所有车辆上实现Setter和Getter方法,所以有更好的方法吗 简化样本: package main import( "reflect" "fmt" ) // the "contract" is that all vehicles have an embedded Engine type Vehicle inter
运行时/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)
}
如果您知道快速的确切类型,您可以使用,并且只有在失败时才恢复到反射
例如:
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
如果有多种可能的“可接受”类型,则可以使用。例如,如果您传递一辆汽车
或*汽车
,则您可以从这两个位置获得功率
值。同样,如果要传递引擎
或*引擎
,同样的情况也适用
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)
}
但是惯用的解决方案仍然是在车辆中添加一个getter函数
:
type Vehicle interface {
GetPower() float64
}
请注意,您不必到处实现GetPower()
。如果在发动机上执行此操作
:
func (e Engine) GetPower() float64 {
return e.Power
}
您将引擎嵌入汽车(就像您所做的那样),您的汽车类型将自动在its中包含此GetPower()
方法(升级),因此它将自动实现汽车。然后您的EngineCheck()
函数将非常简单:
func EngineCheck(v Vehicle) {
fmt.Println(v.GetPower())
}
请在屏幕上尝试这三种变体。我喜欢你答案中惯用的部分。这是一个直截了当的说法。谢谢你,伊卡!