我正在学习Go,我正在阅读Go关于net/http
的官方文档,我在doc中编写以下代码进行测试:
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
方法?
答案 0 :(得分:10)
我真的会先使用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
)。有关详细信息,请参阅Spec: Method declarations。
&
是address operator,它取其操作数的地址。在这种情况下,局部变量client
的类型为*http.Client
。 http.Client{}
是composite literal,它创建结构类型http.Client
的值,&
获取存储此结构值的匿名变量的地址:
复合文字的Taking the address生成一个指向使用文字值初始化的唯一variable的指针。
使用它是为了使client
变量成为指向http.Client
值的指针,鼓励共享和重用它:
客户端的传输通常具有内部状态(缓存的TCP连接),因此应该重用客户端而不是根据需要创建客户端。客户可以安全地同时使用多个goroutine。
如果client
是一个指针,你可以自由地将它传递给其他函数,只会复制指针值,而不是指向的http.Client
结构,所以结构本身({ {1}}值)将被重用。如果您不使用指针,如果您将它传递给其他函数,结构本身将被复制而不会被重用。
请注意,在这个简单的示例中它并不重要,因为即使使用指针接收器声明http.Client
的所有方法,您仍然可以在非指针变量上调用指针方法,如{{1} }将是http.Client
的简写。这在Spec: Calls:
如果
client.Get()
为addressable且(&client).Get()
的方法集包含x
,则&x
是m
的简写。
所以即使在这个简单的例子中不需要x.m()
地址运算符,保持使用它的习惯是好的,如果示例增长,或者你应该编写重要的代码(例如,你传递创建的客户端。)