英文:
How can I access the fields of an interface in Go?
问题
我正在尝试做这个:
if event.Type == sdl.QUIT {
utils.Running = false
}
但是我无法编译,因为我得到了这个错误:
./mm.go:11: event.Type undefined (type sdl.Event has no field or method Type)
这是我尝试使用的库的相关源代码:
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
}
如你所见,所有其他的事件都有Type
字段。我该如何访问它?
解决方案:
这是我最终在这个Go的SDL2绑定库中轮询事件的方式,如果有人想知道的话:
func PollEvents() {
for {
if event := sdl.PollEvent(); event != nil {
switch event.(type) {
case *sdl.QuitEvent:
utils.Running = false
}
} else {
break
}
}
}
英文:
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
. How can I access this?
Solution
This how I ended up polling events in this SDL2 binding for Go, in case anyone is wondering:
func PollEvents() {
for {
if event := sdl.PollEvent(); event != nil {
switch event.(type) {
case *sdl.QuitEvent:
utils.Running = false
}
} else {
break
}
}
}
答案1
得分: 3
实际上你不能这样做。接口只定义了一个类型可用的方法集,它们不能暴露字段。在你的情况下,我建议使用类型切换(type switch)。代码可能会像这样:
switch v := myInstance.(type) {
case CEvent:
fmt.Println(v)
case CommonEvent:
fmt.Println(v)
case WindowEvent:
fmt.Println(v)
default:
fmt.Println("unknown")
}
根据你在此之后对实例的处理方式,你可能需要稍微调整代码结构,但这给出了基本的思路。你也可以对单个类型进行类型断言,例如 v, err := myInstance.(CommonEvent)
,但我怀疑在这里这种方式可能不太有效。此外,如果 myInstance
的类型不是 CommonEvent
,它会返回一个错误,所以这并不是确定类型和接口实例的最佳方法。
英文:
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. 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.
答案2
得分: 1
你需要知道类型。假设我们知道它是一个CEvent:
cEvent, ok := Event.(CEvent)
if !ok {
// 你撒谎了,不是CEvent
return
}
// 否则,你可以获取类型!
fmt.Println(cEvent.Type)
当然,如果你不知道类型,你可以一直进行类型断言,直到找到正确的类型。否则,可以抛出错误、返回默认值等:
func getType(i interface{}) uint32 {
cEvent, ok := i.(CEvent)
if ok {
return cEvent.Type
}
commonEvent, ok := i.(CommonEvent)
if ok {
return commonEvent.Type
}
// 等等
return <默认值>
}
英文:
You will need to know the type. Let's say we know it's a 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>
}
答案3
得分: 1
你可以花很多时间进行反射调用,或者尝试猜测类型,或者使用类型切换。
或者你可以只定义一个包含返回所需信息的函数的接口。
例如,你可以这样做:
type Event interface {
GetCommonEvent() *CommonEvent
GetWindowEvent() *WindowEvent
}
英文:
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
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论