英文:
Pointer to struct satisfy interface
问题
我扫描了Revel框架的Go代码,似乎指针满足接口要求。请看下面的代码片段:
type Result interface {
Apply(req *Request, resp *Response)
}
type RenderTextResult struct {
text string
}
func (r RenderTextResult) Apply(req *Request, resp *Response) {
resp.WriteHeader(http.StatusOK, "text/plain; charset=utf-8")
resp.Out.Write([]byte(r.text))
}
func (c *Controller) RenderText(text string, objs ...interface{}) Result {
finalText := text
if len(objs) > 0 {
finalText = fmt.Sprintf(text, objs...)
}
return &RenderTextResult{finalText}
}
这样做的原因是什么?然而,该框架在渲染JSON时返回的是一个结构体值,而不是结构体指针:
type RenderJsonResult struct {
obj interface{}
callback string
}
// 使用encoding/xml.Marshal将XML返回给客户端。
func (c *Controller) RenderXml(o interface{}) Result {
return RenderXmlResult{o}
}
我似乎无法理解这些微妙的差异。
英文:
I scanned the Revel framework's Go code and it seems that pointers satisfy interface requirements. See the snippets below.
type Result interface {
Apply(req *Request, resp *Response)
}
type RenderTextResult struct {
text string
}
func (r RenderTextResult) Apply(req *Request, resp *Response) {
resp.WriteHeader(http.StatusOK, "text/plain; charset=utf-8")
resp.Out.Write([]byte(r.text))
}
func (c *Controller) RenderText(text string, objs ...interface{}) Result {
finalText := text
if len(objs) > 0 {
finalText = fmt.Sprintf(text, objs...)
}
return &RenderTextResult{finalText}
}
What's the reasoning behind this? The framework is returning a struct value instead of a struct pointer for rendering JSON, though:
type RenderJsonResult struct {
obj interface{}
callback string
}
// Uses encoding/xml.Marshal to return XML to the client.
func (c *Controller) RenderXml(o interface{}) Result {
return RenderXmlResult{o}
}
I can't seem to grasp the subtle (?) differences.
答案1
得分: 3
是的,指针隐式地具有它们所指向类型的所有方法。请参阅FAQ部分中的"为什么T和*T具有不同的方法集?"和"值或指针上的方法?"。
英文:
Yes, pointers implicitly have all the methods of the type they point to. See the FAQ sections "Why do T and *T have different method sets?" and "Methods on values or pointers?"
答案2
得分: 2
与类型相关联的方法也可以在指向该类型的指针上使用。所以如果r
是一个*RenderTextResult
变量,那么r.Apply(...)
等同于(*r).Apply()
。
在大多数情况下,Apply
方法的行为与直接与*RenderTextResult
相关联的方法相似,尽管它无法修改结构体的内容,因为它接收的是结构体的副本而不是指向原始结构体的指针。
这意味着可以使用RenderTextResult
上的方法来使*RenderTextResult
满足Result
接口。
英文:
Methods associated with a type are also available on pointers to that type. So if r
is a *RenderTextResult
variable, then r.Apply(...)
is equivalent to (*r).Apply()
.
In most respects, the Apply
method will act like any method associated with *RenderTextResult
directly, although it won't be able to modify the contents of the struct, since it receives a copy of the struct rather than a pointer to the original.
This means that the methods on RenderTextResult
can be used to let *RenderTextResult
satisfy the Result
interface.
答案3
得分: 1
任何命名类型都可以满足一个接口。无论类型是指针、通道还是函数值,只要它实现了接口要求的方法即可。
以下是一个满足接口的函数示例(play):
type Printer interface {
Print(string)
}
type funcPrinter func() string
func (f funcPrinter) Print(s string) {
fmt.Println(s + f())
}
这引出了一个问题,为什么要返回指针而不是值,或者反过来。如果你一直在传递对象,那么使用指针是一个好主意,因为它们始终具有固定的小长度,而不是所有的值。
以下代码将导致将结构体复制到调用者:
return RenderXmlResult{o}
而这个调用将返回指向堆中某个位置的结构体指针:
return &RenderXmlResult{o}
英文:
Any named type can satisfy an interface. It does not matter whether the type is a pointer, a channel or a function value as long as it implements the methods the interface demands.
Example of a function satisfying an interface (play):
type Printer interface {
Print(string)
}
type funcPrinter func() string
func (f funcPrinter) Print(s string) {
fmt.Println(s + f())
}
This leaves the question why one would return a pointer rather than a value or vice versa.
If you pass objects around all the time then it is a good idea to use pointers as they are
always of a small fixed length instead of all the values.
The following line results in having the struct copied to the caller:
return RenderXmlResult{o}
While this call will return a pointer to the struct placed somewhere in the heap.
return &RenderXmlResult{o}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论