如何在Go中引用接口类型?

huangapple go评论71阅读模式
英文:

How can I refer to an interface type in Go?

问题

我有这两种类型:

type Routing map[string]Handler

type Handler interface {
	Handle()
}

我有一个叫做MyHandler的类型,它满足这个接口,看起来像这样:

type MyHandler struct {
}

func (this *MyHandler) Handle() {
	// ...
}

我想要能够像这样做一些事情:

// routes在程序开始时创建,并在脚本的整个生命周期中可用

routes := Routing {
	"/route/here": MyHandler,
})

// ...

// 在另一个方法中,这一行可能会执行多次:

new(routes["/route/here"]).Handle()

我在最后一行得到这个错误:

routes["/route/here"]不是一个类型

当我将最后一行改为

routes["/route/here"].Handle()

显然它可以工作。然而,它只使用一个Handler的实例...而我希望每次执行最后一行时都实例化一个新的Handler。我该如何在每次执行最后一行时实例化一个新的Handler

(我假设使用new时,旧的实例将在使用后被垃圾回收。请注意,我没有保存我创建的实例;我只关心调用Handle()方法然后销毁它。)

英文:

I have these two types:

type Routing map[string]Handler

type Handler interface {
	Handle()
}

I have a type called MyHandler which satisfies the interface, and it looks like this:

type MyHandler struct {
}

func (this *MyHandler) Handle() {
	// ...
}

I'd like to be able to do something like this:

// routes is created at the beginning of the program and available
// throughout the lifetime of the script

routes := Routing {
	"/route/here": MyHandler,
})

// ...

// and in another method, this line may be executed several times:

new(routes["/route/here"]).Handle()

I get this error on the last line:

> routes["/route/here"] is not a type

When I change that last line to

routes["/route/here"].Handle()

it obviously works. However, it uses just one instance of the Handler forever... and I wish for a new instance every time that last line is executed. How can I instantiate a new instance of the Handler each time that last line is executed?

(I assume that when using new, the old ones will be garbage-collected after use. Notice that I'm not saving the instance I create; I only care to call the Handle() method then have it destroyed.)

答案1

得分: 5

new()以类型作为参数,并返回该类型的一个零值的指针。在Go语言中,类型不是一等值。New是一个内置函数,所以它不遵循其他代码的规则。New在编译时需要知道它将要处理的类型。没有办法构建一个类型的映射。

我的建议是使用一个函数来构建每个类型。

type Routing map[string]func() Handler
routes := Routing {
    "/route/here": func() Handler { return new(MyHandler)},
}

routes["/route/here"]().Handle()

我们不是在构建一个类型的映射,而是在构建一个返回我们想要的类型的函数的映射。


另一种可能性是使用反射,尽管我更喜欢上面的函数方法。对于这种用例,我认为使用反射是滥用。

type Routing map[string]reflect.Type
routes := Routing {
    "/route/here": reflect.TypeOf(MyHandler{}),
}

reflect.New(routes["/route/here"]).Interface().(Handler).Handle()

警告,如果MyHandler没有实现Handler接口,这将导致程序崩溃。这种方法放弃了编译时类型检查。

英文:

new() takes a type as a parameter and returns a pointer to a zeroed out value of that type. Types are not first class values in Go. New is a builtin so it doesn't play by the same rules other code does. New needs to know at compile time what type it will be working on. There is no way to build a map of types.

My suggestion would be to use a function to build each type.

type Routing map[string]func() Handler
routes := Routing {
    "/route/here": func() Handler { return new(MyHandler)},
}

routes["/route/here"]().Handle()

Instead of building a map of types, we are building a map of functions that return the type we want.


Another possibility is to use reflect although I like the function method above better. For this use case I believe it would be an abuse of reflect.

type Routing map[string]reflect.Type
routes := Routing {
    "/route/here": reflect.TypeOf(MyHandler{}),
}

reflect.New(routes["/route/here"]).Interface().(Handler).Handle()

Warning, this will crash your program if MyHandler does not implement Handler. This method gives up compile time type checking.

huangapple
  • 本文由 发表于 2013年6月14日 10:49:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/17100371.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定