英文:
Pointer receiver and Value receiver difference in implementation with Iris framework
问题
我最近在学习Iris框架。在实现Handler时遇到了一个问题,就像下面的代码一样:
package controller
import "github.com/kataras/iris"
type Pages struct{
}
func (p *Pages) Serve(c *iris.Context) {
}
为了使用这个控制器,我实现了以下入口脚本:
package main
import (
"github.com/kataras/iris"
"web/controller"
)
func main(){
ctrl := controller.Pages{}
iris.Handle("GET", "/", ctrl)
iris.Listen(":8080")
}
但是当我编译代码时,我得到了以下错误信息:
cannot use ctrl (type controllers.Pages) as type iris.Handler in argument to iris.Handle:
controllers.Pages does not implement iris.Handler (Serve method has pointer receiver)
在我将声明更改为以下内容之后:
ctrl := &controller.Pages{}
然后编译器通过了,没有任何投诉。
问题是:我认为以下语句是相等的,因为GO编译器会在幕后进行转换:
type Pages struct {
}
func (p *Pages) goWithPointer() {
fmt.Println("goWithPointer")
}
func (p Pages) goWithValue() {
fmt.Println("goWithValue")
}
func main() {
p1 := Pages{}
p2 := &Pages{}
p1.goWithPointer()
p1.goWithValue()
p2.goWithPointer()
p2.goWithValue()
}
为什么我不能使用ctrl := controller.Pages{}
作为iris.Handle()
的参数,而要使用ctrl := &controller.Pages{}
作为iris.Handle()
的参数?
谢谢你的时间和分享。
英文:
I am studying Iris framework recently. I encountered a question when I was implementing the Handler. Like following:
<!-- language: lang-golang -->
package controller
import "github.com/kataras/iris"
type Pages struct{
}
func (p *Pages) Serve(c *iris.Context) {
}
In order to use this controller, I implemented the following entry script:
<!-- language: lang-golang -->
package main
import (
"github.com/kataras/iris"
"web/controller"
)
func main(){
ctrl := controller.Pages{}
iris.Handle("GET", "/", ctrl)
iris.Listen(":8080")
}
But when I compiled the code, I got the following error message:
cannot use ctrl (type controllers.Pages) as type iris.Handler in argument to iris.Handle:
controllers.Pages does not implement iris.Handler (Serve method has pointer receiver)
After I changed the declaration to:
ctrl := &controller.Pages{}
Then the compiler passed with no complaint.
The question is: I thought the following statements are equal, since the GO compiler will do the conversion under the table:
<!-- language: lang-golang -->
type Pages struct {
}
func (p *Pages) goWithPointer() {
fmt.Println("goWithPointer")
}
func (p Pages) goWithValue() {
fmt.Println("goWithValue")
}
func main() {
p1 := Pages{}
p2 := &Pages{}
p1.goWithPointer()
p1.goWithValue()
p2.goWithPointer()
p2.goWithValue()
}
Why can't I use ctrl := controller.Pages{}
as the parameter to iris.Handle()
, instead of ctrl := &controller.Pages{}
as the parameter to iris.Handle()
?
Thank you for your time and sharing.
答案1
得分: 2
查看文档:
> 一个类型可以有一个与之关联的方法集。接口类型的方法集就是它的接口。任何其他类型 T
的方法集由所有声明了接收器类型为 T
的方法组成。相应指针类型 *T
的方法集是所有声明了接收器为 *T
或 T
的方法的集合(也就是说,它还包含了 T
的方法集)。对于包含匿名字段的结构体,还有其他规则,详见结构体类型的章节。其他任何类型都有一个空的方法集。在方法集中,每个方法必须有一个唯一的非空方法名。
并参见:https://stackoverflow.com/a/33591156/6169399:
> 如果你有一个接口 I
,并且 I
的方法集中的一些或全部方法是由具有接收器为 *T
的方法提供的(其余方法由具有接收器为 T
的方法提供),那么 *T
满足接口 I
,但 T
不满足。这是因为 *T
的方法集包括 T
的方法集,但反过来不成立。
使用 ctrl := Pages{}
会出错:
cannot use ctrl (type Pages) as type Handler in argument to Handle:
Pages does not implement Handler (Serve method has pointer receiver)
使用 ctrl := Pages{}
需要:
func (p Pages) Serve() {
fmt.Println(p.i)
}
Iris Handler 是一个接口类型。像这个工作示例一样(见注释):
<!-- language: lang-golang -->
package main
import "fmt"
type Handler interface {
Serve()
}
type Pages struct {
i int
}
func (p *Pages) Serve() {
fmt.Println(p.i)
}
func Handle(p Handler) {
p.Serve()
}
func main() {
// cannot use ctrl (type Pages) as type Handler in argument to Handle:
// Pages does not implement Handler (Serve method has pointer receiver)
//ctrl := Pages{}
ctrl := &Pages{101}
Handle(ctrl)
}
输出:
101
英文:
> A type may have a method set associated with it. The method set of an
> interface type is its interface. The method set of any other type T
> consists of all methods declared with receiver type T
. The method set
> of the corresponding pointer type *T
is the set of all methods
> declared with receiver *T
or T
(that is, it also contains the method
> set of T
). Further rules apply to structs containing anonymous fields,
> as described in the section on struct types. Any other type has an
> empty method set. In a method set, each method must have a unique
> non-blank method name.
And see: https://stackoverflow.com/a/33591156/6169399 :
> If you have an interface I
, and some or all of the methods in I
's
> method set are provided by methods with a receiver of *T
(with the
> remainder being provided by methods with a receiver of T
), then *T
> satisfies the interface I
, but T
doesn't. That is because *T
's method
> set includes T
's, but not the other way around.
Using ctrl := Pages{}
makes error:
cannot use ctrl (type Pages) as type Handler in argument to Handle:
Pages does not implement Handler (Serve method has pointer receiver)
Using ctrl := Pages{}
needs:
func (p Pages) Serve() {
fmt.Println(p.i)
}
Iris Handler is an interface type. like this working sample (see comment):
<!-- language: lang-golang -->
package main
import "fmt"
type Handler interface {
Serve()
}
type Pages struct {
i int
}
func (p *Pages) Serve() {
fmt.Println(p.i)
}
func Handle(p Handler) {
p.Serve()
}
func main() {
// cannot use ctrl (type Pages) as type Handler in argument to Handle:
// Pages does not implement Handler (Serve method has pointer receiver)
//ctrl := Pages{}
ctrl := &Pages{101}
Handle(ctrl)
}
output:
101
答案2
得分: 0
根据https://godoc.org/github.com/kataras/iris#Handler,Iris Handler是一个接口类型。
Go只对变量进行隐式指针转换,而不对接口进行转换。
英文:
According to https://godoc.org/github.com/kataras/iris#Handler. Iris Handler is an interface type.
GO performs implicit pointer-conversion on variables only, not on interfaces.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论