英文:
Why is http.Client{} prefixed with &?
问题
我正在学习Go语言,并阅读Go的官方文档关于net/http
的部分,我从文档中复制了以下代码进行测试:
package main
import (
"net/http"
"fmt"
)
func main() {
client := &http.Client{}
resp, _ := client.Get("http://example.com")
fmt.Println(resp)
}
http.Client
是一个结构体,但我不知道为什么前面有一个&
指针前缀。我认为创建一个http.Client
的引用是不必要的。而且为什么client
变量有一个Get
方法?我正在阅读net/http
的源代码,它定义了下面的Client
结构体:
type Client struct {
Transport RoundTripper
CheckRedirect func(req *Request, via []*Request) error
Jar CookieJar
Timeout time.Duration
}
Client
结构体没有定义Get
方法,为什么client
变量有一个Get
方法?
英文:
I am learning Go and I am reading Go's official documentation about net/http
, and I write following code from doc for test:
package main
import (
"net/http"
"fmt"
)
func main() {
client := &http.Client{}
resp, _ := client.Get("http://example.com")
fmt.Println(resp)
}
http.Client
is a struct, but I do not know why there is a &
pointer prefixed. I think creating a http.Client
reference is not necessary. And why does the client
variable have a Get
method? I am reading the source code of net/http
, it defines the Client
struct below:
type Client struct {
Transport RoundTripper
CheckRedirect func(req *Request, via []*Request) error
Jar CookieJar
Timeout time.Duration
}
The Client
struct does not have a Get
method defined; why does the client
variable have a Get
method?
答案1
得分: 20
我会帮你翻译以下内容:
我首先建议你参加Go Tour,以了解该语言及其基本语法。
你引用的类型声明只包含结构体的字段,而不包含其方法。方法在其他地方定义,类似于函数,但添加了一个接收器(receiver),用于指定它们所属的类型。例如,Client.Get()
方法的定义如下:
func (c *Client) Get(url string) (resp *Response, err error) {
req, err := NewRequest("GET", url, nil)
if err != nil {
return nil, err
}
return c.Do(req)
}
方法名前面的部分称为接收器,用于指定方法所属的类型(在这个例子中是 *Client
)。详细信息请参阅规范:方法声明。
&
是一个取地址运算符,它获取操作数的地址。在这种情况下,局部变量 client
的类型将是 *http.Client
。http.Client{}
是一个复合字面量,它创建了一个 http.Client
结构体类型的值,并且 &
取得了存储此结构体值的匿名变量的地址:
取复合字面量的地址会生成一个指向具有该字面量值的唯一变量的指针。
这样做是为了使 client
变量成为指向 http.Client
值的指针,鼓励共享和重用:
客户端的传输通常具有内部状态(缓存的 TCP 连接),因此应该重用而不是根据需要创建客户端。客户端可以安全地供多个 goroutine 并发使用。
如果 client
是一个指针,你可以自由地将其传递给其他函数,只会复制指针值,而不会复制指向的 http.Client
结构体,因此结构体本身(http.Client
值)将被重用。如果不使用指针,如果将其传递给其他函数,将复制结构体本身而不是重用。
请注意,在这个简单的例子中,实际上并不重要,因为即使 http.Client
的所有方法都是使用指针接收器声明的,你仍然可以在非指针变量上调用指针方法,例如 client.Get()
相当于 (&client).Get()
。这在规范:调用中有提到:
如果
x
是可寻址的,并且&x
的方法集包含m
,则x.m()
是(&x).m()
的简写形式。
因此,即使在这个简单的例子中不需要使用 &
地址运算符,养成使用它的习惯是好的,因为如果示例变得更复杂,或者你编写的代码确实需要这样(例如,你传递创建的客户端),这将很有用。
英文:
I would really take the Go Tour to get a feeling of the language and its basic syntax first.
The type declaration you quoted only contains the fields of the struct, but not its methods. Methods are defined elsewhere, like functions but with a receiver added which designates the type they belong to. For example the definition of Client.Get()
method is this:
func (c *Client) Get(url string) (resp *Response, err error) {
req, err := NewRequest("GET", url, nil)
if err != nil {
return nil, err
}
return c.Do(req)
}
The part before the method name is called the receiver, and that designates the type the method belogns to (*Client
in this example). See Spec: Method declarations for more details.
The &
is an address operator, it takes the address of its operand. In this case the local variable client
will be of type *http.Client
. http.Client{}
is a composite literal which creates a value of the struct type http.Client
, and &
takes the address of the anonymous variable where this struct value is stored:
> Taking the address of a composite literal generates a pointer to a unique variable initialized with the literal's value.
It is used so that the client
variable will be a pointer to an http.Client
value, one that is encouraged to be shared and reused:
> The Client's Transport typically has internal state (cached TCP connections), so Clients should be reused instead of created as needed. Clients are safe for concurrent use by multiple goroutines.
And if client
is a pointer, you are free to pass it around to other functions, only the pointer value will be copied, not the pointed http.Client
struct, so the struct itself (the http.Client
value) will be reused. Should you not use a pointer, if you would pass it to other functions, the struct itself would be copied and not reused.
Note that in this simple example it doesn't really matter, as even though all methods of http.Client
are declared with pointer receiver, you can still call pointer methods on non-pointer variables, as client.Get()
would be a shorthand for (&client).Get()
. This is mentioned in Spec: Calls:
> If x
is addressable and &x
's method set contains m
, x.m()
is shorthand for (&x).m()
.
So even though the &
address operator is not needed in this simple example, it's good to keep the habit of using it, should the example grow or should you write code where this does matter (e.g. you pass around the created client).
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论