为什么http.Request参数必须是一个指针?

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

Why must the http.Request argument be a pointer?

问题

package main

import (
	"net/http"
)

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request){
		w.Write([]byte("hello world"))
	})
	http.ListenAndServe(":8000", nil)
}

如果我在http.Request中删除*

github.com/creating_web_app_go/main.go:8: cannot use func literal (type func(http.ResponseWriter, http.Request)) as type func(http.ResponseWriter, *http.Request) in argument to http.HandleFunc

我对Go和指针都非常陌生。

所以问题是,为什么http.Request必须是一个指针而不是一个func literal?有人能以最简单的方式解释一下吗,最好附带源代码的参考?

英文:
package main

import (
	"net/http"
)

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request){
		w.Write([]byte("hello world"))
	})
	http.ListenAndServe(":8000", nil)
}

If I remove the * in http.Request:

> github.com/creating_web_app_go/main.go:8: cannot use func literal (type func(http.ResponseWriter, http.Request)) as type func(http.ResponseWriter, *http.Request) in argument to http.HandleFunc

I'm very new to both Go and pointers.

So the Question is,
why must http.Request be a pointer rather than a func literal? Can anyone explain this in the simplest way possible, with perhaps a reference to source code?

答案1

得分: 16

因为它是一个大的结构体。复制它会很昂贵。所以它是一个指向结构体的指针,在Go语言中,当结构体很大时,这是常见的做法。此外,它还具有一些状态,如果复制它可能会导致混淆。它作为一个函数字面量是没有意义的;我不明白为什么会有这个选项。

英文:

Because it's a large struct. Copying it would be expensive. So it's a pointer to a struct, which is common in Go when structs are large. Also it has some state, so it would likely be confusing if it were copied. It would make no sense to be a func literal; I don't understand why that would be an option.

答案2

得分: 3

因为这就是函数的工作方式。它们有参数,当你调用它们时,必须提供所需的参数。类型也必须相同。

我认为你真正想问的是:为什么设计成这样?

因为你正在为http.HandleFunc提供一个委托,在根路径"/"收到请求时调用它。在大多数情况下,当一个RESTful API处理请求时,它需要知道请求中的信息,比如头部、查询参数和/或请求体... 如果你不想使用这些信息,你也可以不用,将一个引用传递给函数并不会增加太多开销。但对于几乎所有真实的用例,数据是必需的,所以它被包含在你提供的委托的参数中。从实现的角度来看,他们需要知道你提供的方法签名是什么,这样他们才能调用它。

所以,为了澄清,你看到的东西是作为http.HandleFunc的第二个参数提供的func的必需签名。第一个参数是路径。当收到一个http请求时,它会调用该方法。这段代码将调用该参数,并将其称为handler,它需要一个一致的定义,以便可以执行handler(resp, req),而不需要进行反射、switch或其他控制流来调用你的代码。

英文:

Because that's how functions work. They have arguments and when you invoke them you must provide the required arguments. The types have to be the same as well.

I think you're really asking; Why is it designed that way?

Because you're providing a delegate for http.HandleFunc to invoke when a request is made to the root "/". In most cases when a RESTful API is handling a request it needs to know information in the request, stuff like the headers, query parameters and/or post body... If you don't want to make use of that information you don't have to, it's not much overhead to pass a reference into a function. But for just about every real use case, the data is needed so it's included, so it is made an argument in the delegate you provide. From the persepctive of their implemenation, they need to know what the method signature is that you provide so they can invoke it.

So to clarify, the thing you're looking at is the required signature for the func you provide as the second argument to http.HandleFunc. The first argument is the path. It invokes that method when an http request is made to the provided path. That code is going to call that argument call it handler and it needs a consistent definition so that it can do handler(resp, req) and not have to do reflection or a switch or some other control flow just to call into your code.

huangapple
  • 本文由 发表于 2015年7月1日 02:18:32
  • 转载请务必保留本文链接:https://go.coder-hub.com/31145564.html
匿名

发表评论

匿名网友

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

确定