通过界面

时间:2016-02-15 07:35:04

标签: reflection go struct interface embedding

似乎我错过了一些重要的东西,但我无法弄清楚它是什么。我使用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)
}

1 个答案:

答案 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上尝试所有这三种变体。