Go 返回具有数据成员的多态类型
我试图编写一个函数getTargetServer来返回一个多态类型,该多态类型既有一个数据成员URL,也有一个方法Close。这将是从返回的泛化,但我希望能够返回一个自定义类型,Close是NOPGo 返回具有数据成员的多态类型,go,polymorphism,Go,Polymorphism,我试图编写一个函数getTargetServer来返回一个多态类型,该多态类型既有一个数据成员URL,也有一个方法Close。这将是从返回的泛化,但我希望能够返回一个自定义类型,Close是NOP type externalTestServer struct { URL string } func (externalTestServer) Close() {} func getTargetServer() *externalTestServer { if urlbase, o
type externalTestServer struct {
URL string
}
func (externalTestServer) Close() {}
func getTargetServer() *externalTestServer {
if urlbase, ok := optionals["urlbase"].(string); ok {
return &externalTestServer{URL: urlbase}
} else {
testServer := httptest.NewServer(newMyServerHandler())
// return testServer // ### Error ###
return &externalTestServer{URL: testServer.URL}
}
}
func Test_health_check(t *testing.T) {
testServer := getTargetServer()
defer testServer.Close()
response, err := http.Get(testServer.URL + "/health")
assert.NilError(t, err)
assert.Assert(t, cmp.Equal(response.StatusCode, http.StatusOK))
}
这就像一个魅力,除了关闭总是一个不。当我取消注释指示的错误行以返回closable*服务器时,会收到以下错误消息:
无法在返回参数中使用testServer类型*httptest.Server作为类型*externalTestServer
我理解这个错误,但还没有发现一个解决方案,可以让我返回一个泛化*服务器的多态类型
注:Go之旅定义了如下接口类型:
接口类型定义为一组方法签名
因此,返回一个简单接口将不允许直接访问数据成员。http.Server是一个结构,因此您不能返回概括该结构的多态对象。不过,您可以做其他事情:
type Server interface {
GetURL() string
Close() error
}
type testServer struct {
URL string
}
func (t testServer) Close() error {}
func (t testServer) GetURL() string {return t.URL}
type httpServer struct {
*http.Server
}
func (t httpServer) GetURL() string { return the url }
然后,您可以从函数返回服务器。您可以创建一个结构,该结构包含一个字段,该字段是字符串URL,该字段是关闭函数。Close func可以由externalTestServer或httptest实现。服务器:
Chris Drew的方法非常适合这种情况,因为它需要最小的代码开销。换句话说,这是解决当今问题的最简单的办法。该解决方案使用隐式闭包的魔力,让接收方以多态方式引用Close的实现 我稍微简化的版本在这里
type genericServer struct {
URL string // snapshot of internal data
Close func() // single-function polymorphism without 'interface'
}
func getTargetServer() genericServer {
if urlbase, ok := optionals["urlbase"].(string); ok {
return genericServer{URL: urlbase, Close: func() {}}
}
testServer := httptest.NewServer(newMyServerHandler())
return genericServer{URL: testServer.URL, Close: testServer.Close}
}
通过将实际接口类型嵌入to return结构,可以无缝地扩展此概念,以更好地支持非平凡多态接口。在这种情况下,多态性是基于接口类型的内部使用而显式的。尽管如此,返回的类型是一个包含常量成员数据副本的包装器,因此其用法是相同的——有效地概括了此用例的用法
type Server interface {
Close()
}
type nopServer struct {
}
func (nopServer) Close() {}
type genericServer struct {
URL string // snapshot of specific data
Server // embedded interface type for explicit polymorphism
}
func getTargetServer() genericServer {
if urlbase, ok := optionals["urlbase"].(string); ok {
return genericServer{URL: urlbase, Server: nopServer{}}
}
testServer := httptest.NewServer(newMyServerHandler())
return genericServer{URL: testServer.URL, Server: testServer}
}
请注意,URL值不是实现的活动成员,因此这些解决方案仅在数据值不会更改时才有意义,尽管使用指针可能会克服这一限制。Go中多态性的唯一形式是接口,接口只描述行为;他们不可能有字段。-2:以这种速度,我永远不会变得好奇:回答得好。这与我最初认为必须采取的方法类似。虽然为东西创建额外的包装器有点笨重,但这不是我的偏好。这似乎完全符合我的期望-而且构造非常简单。甚至不需要externalTestServer-可以使用Close:func{}来创建NOP。
type genericServer struct {
URL string // snapshot of internal data
Close func() // single-function polymorphism without 'interface'
}
func getTargetServer() genericServer {
if urlbase, ok := optionals["urlbase"].(string); ok {
return genericServer{URL: urlbase, Close: func() {}}
}
testServer := httptest.NewServer(newMyServerHandler())
return genericServer{URL: testServer.URL, Close: testServer.Close}
}
type Server interface {
Close()
}
type nopServer struct {
}
func (nopServer) Close() {}
type genericServer struct {
URL string // snapshot of specific data
Server // embedded interface type for explicit polymorphism
}
func getTargetServer() genericServer {
if urlbase, ok := optionals["urlbase"].(string); ok {
return genericServer{URL: urlbase, Server: nopServer{}}
}
testServer := httptest.NewServer(newMyServerHandler())
return genericServer{URL: testServer.URL, Server: testServer}
}