Go语言中'*'与'&'符号的含义及函数返回指针类型的原因
net/http.NewRequest) 我当初刚学Go的时候也对这个点纠结过,既然你已经懂了指针接收器能修改指向的值,那咱们就顺着这个思路,拆解下函数返回指针的核心原因:
1. 避免大对象拷贝带来的性能损耗
像http.Request这种结构体,内部包含了Header、Body、URL、Cancel等一大堆字段,要是函数返回值类型,每次调用都会完整拷贝整个结构体到调用栈里——这对于频繁创建请求的场景来说,是不小的性能浪费。而返回指针的话,只需要拷贝一个8字节(64位系统)的内存地址,成本低得多。
2. 允许调用者修改返回的对象
你想想,创建完请求后,咱们通常要做什么?加请求头、设置超时、修改URL参数对吧?如果NewRequest返回的是值类型,那你修改的只是拷贝后的副本,原对象根本没变化——这就意味着你做的这些修改完全无效,发送请求的时候还是用的最初的默认值。
比如这段代码如果返回值类型就会出问题:
req, err := http.NewRequest("GET", "https://example.com", nil) if err != nil { // 处理错误 } req.Header.Add("Authorization", "Bearer my-token") // 这里修改的是副本,原请求对象没变化
但返回指针的话,你操作的就是NewRequest内部创建的那个真实对象,修改会直接生效,符合咱们的预期。
3. 用nil表示“无效/不存在”的状态
Go里值类型的结构体没法直接表示“空”的状态——哪怕你初始化一个零值结构体,它也还是一个合法的对象。但指针可以返回nil,用来明确表示函数创建对象失败的情况。比如NewRequest如果解析URL失败,就会返回nil和对应的error,调用者一眼就能判断请求对象是否有效:
req, err := http.NewRequest(...) if err != nil || req == nil { // 处理创建失败的情况 }
4. 符合Go的惯用设计风格
在Go的标准库中,对于复杂、可变的结构体,几乎都会用指针来传递和返回。这样做能保持代码的一致性:你拿到指针后,后续调用其他相关函数(比如client.Do(req))时,不需要额外做值转指针的操作,代码更简洁流畅。
总结一下,返回指针本质上是为了性能优化、支持修改、明确空状态这几个核心需求,而net/http.NewRequest刚好同时满足这些场景~
内容的提问来源于stack exchange,提问作者user2989731

