简体   繁体   English

如何在Go中访问界面的字段?

[英]How can I access the fields of an interface in Go?

I'm trying to do this: 我正在尝试这样做:

if event.Type == sdl.QUIT {
    utils.Running = false
}

But I can't because when I try to build, I get this error: 但是我不能,因为当我尝试构建时,出现以下错误:

 ./mm.go:11: event.Type undefined (type sdl.Event has no field or method Type)

Here is the relevant source code of the library I'm trying to use: 这是我要使用的库的相关源代码:

type Event interface{}    

type CEvent struct {
    Type uint32
    _    [52]byte // padding
}

type CommonEvent struct {
    Type      uint32
    Timestamp uint32
}

// WindowEvent (https://wiki.libsdl.org/SDL_WindowEvent)
type WindowEvent struct {
    Type      uint32
    Timestamp uint32
    WindowID  uint32
    Event     uint8
    _         uint8 // padding
    _         uint8 // padding
    _         uint8 // padding
    Data1     int32
    Data2     int32
}

As you can see, all of the other Events have the field Type . 如您所见,所有其他事件都具有字段Type How can I access this? 我该如何访问?

Solution

This how I ended up polling events in this SDL2 binding for Go , in case anyone is wondering: 这样我就可以在此SDL2绑定中轮询Go的事件,以防万一有人在想:

func PollEvents() {
    for {
        if event := sdl.PollEvent(); event != nil {
            switch event.(type) {
            case *sdl.QuitEvent:
                utils.Running = false
            }
        } else {
            break
        }
    }
}

You actually can't. 你实际上不能。 Interfaces only define a method set that is available on a type, they do nothing to expose fields. 接口仅定义一种类型可用的方法集,它们不执行任何公开字段的操作。 In your case I would recommend doing a type switch. 在您的情况下,我建议您进行类型切换。 It would look a little like this; 看起来有点像这样;

     switch v := myInstance.(type) {
                case CEvent:
                        fmt.Println(v)
                case CommonEvent:
                        fmt.Println(v)
                case WindowEvent:
                        fmt.Println(v)
                default:
                        fmt.Println("unknown")
        }

You may want to structure your code a bit differently depending on what you're doing with the instance after this but that gives you the basic idea. 您可能要根据此后对实例的处理方式对代码进行一些不同的构造,但这可以为您提供基本的思想。 You can also do a type assertion with a single type like; 您也可以对单个类型进行类型断言,例如; v, err := myInstance.(CommonEvent) but I doubt it would be as effective here. v, err := myInstance.(CommonEvent)但我怀疑它在这里是否会有效。 It also returns an error if the type of myInstance is not CommonEvent so it's not really the best way to go about figuring out what type and interface instance may be. 如果myInstance的类型不是CommonEvent ,它还会返回一个错误,因此,这并不是弄清楚类型和接口实例可能是什么的最佳方法。

You will need to know the type. 您将需要知道类型。 Let's say we know it's a CEvent: 假设我们知道这是一个CEvent:

cEvent, ok := Event.(CEvent)
if !ok {
    // You lied, not a CEvent
    return
}

// Otherwise, you can get the type!
fmt.Println(cEvent.Type)

Of course if you don't know the type, you can keep type asserting until you get it right. 当然,如果您知道类型,则可以保持类型断言,直到正​​确为止。 Otherwise, throw an error, return a default value, etc: 否则,抛出错误,返回默认值,等等:

func getType(i interface{}) uint32 {
    cEvent, ok := i.(CEvent)
    if ok {
        return cEvent.Type
    }

    commonEvent, ok := i.(CommonEvent)
    if ok {
        return commonEvent.Type
    }

    // Etc

    return <default>
}

You can spend a lot of time doing reflection calls or trying to guess the type or using type switches. 您可以花费大量时间进行反射调用或尝试猜测类型或使用类型开关。

Or you can just define an interface with functions that return the information you need. 或者,您可以只定义一个带有返回所需信息的函数的接口。

For example you could do 例如你可以

type Event interface {
    GetCommonEvent() *CommonEvent
    GetWindowEvent() *WindowEvent
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM