通过接口访问嵌入式类型字段

问题描述 投票:1回答:1

好像我错过了重要的东西,但我无法弄清楚它是什么。我使用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)
}
reflection go struct interface embedding
1个回答
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类型将自动在其GetPower()中使用这个method set方法(提升),因此它将自动实现Vehicle。然后你的EngineCheck()函数就像这样简单:

func EngineCheck(v Vehicle) {
    fmt.Println(v.GetPower())
}

Go Playground上尝试所有这三种变体。

© www.soinside.com 2019 - 2024. All rights reserved.