赞
踩
如 http.Handler 接口,有个困惑,为什么 第一个参数是value类型,第二个参数是指针类型呢?
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
Go里一切传递,都是传值,即便是指针。其实指针是一种特殊的类型包含了地址的值。
更进一步的发现,ResponseWriter 是接口类型。
type ResponseWriter interface {
Header() Header
Write([]byte) (int, error)
WriteHeader(int)
}
interface 在运行时,会保存一个实现接口的对象,结构体里有两行,一个指向类型,另一个指向它关联的数据。
如果没有任何的数据绑定在接口上,Go可以指示接口实现,并提供编译时候的类型检查。
//(1) The interface type Mutable interface { mutate(newValue string) error } //(2) Struct type Data struct { name string } //(3) Implements the interface with a pointer receiver func (d *Data) mutate(newValue string) error { d.name = newValue return nil } //(4) Function that accepts the interface func mutator(mute Mutable) error { return mute.mutate("mutate") } func main() { d := Data{name: "fresh"} fmt.Println(d.name) //fresh //(5) pass as a pointer mutator(&d) fmt.Println(d.name) //mutate }
在第三步,Data 实现了指针,可以改变内部的值
在第四步,函数 mutator 接受一个参数,来执行真正的改变操作。注意这里的参数是一个值,而不是指针。
第五步,我们传递了一个指针进去。貌似它违反了通常的golang 类型检查 type-check。例如,传递正常的类型会失败,但是传递接口是可以成功的。
例如下面的,就会编译失败
func thisWontWork(s string) { ... }
v := "kirk"
thisWontWork(&v) //compilation error
参数的类型检查,确保参数 interface 和 结构体的 receiver 一致。
---------------------------------------------
| method receiver | parameter |
| ------------------------------------------|
| pointer | pointer |
|-------------------------------------------|
| value | value |
| | pointer (dereferenced) |
---------------------------------------------
让测一下上述的假设,通过改变 receiver 为一个 值类型,并传参为值。
//(1) Implements the interface with a value receiver
func (d Data) mutate(newValue string) error {
...
//(2) mutator function is UNCHANGED
func mutator(mute Mutable) error {
//(3) pass as value
mutator(d)
fmt.Println(d.name) //fresh
你仍然可以看到,这个结构体,同样符合 mutator 函数的要求。但是该函数可能不太符合我们要求了,因为原始的值没有改变。
以下会编译错误:
//(1) Implements the interface with a pointer receiver
func (d *Data) mutate(newValue string) error {
//(2) Function is UNCHANGED
func mutator(mute Mutable) error {
//(3) Pass as value. Results in compilation error.
mutator(d)
interface 的实现者,可以有不同的类型的receivers
//(1) Define another struct that implements the interface
type AnotherData struct {...}
//(2) Implements as a value receiver.
func (ad AnotherData) mutate(newValue string) error {...}
//(3) Function is UNCHANGED
func mutator(mute Mutable) error {...}
//(4) Pass as a value.
anotherData := AnotherData{name: "afresh"}
fmt.Println(anotherData.name) //afresh
mutator(anotherData)
fmt.Println(anotherData.name) //afresh
回到最初我们讨论的 Handler, 这里的response 结构体实现了 ResponseWriter 接口,同样带着 指针类型的receivers
【这里要解释 receiver和函数的区别】
Http Server 生成了一个 返回结构体,然后作为一个指针传递给handlers,这样可以使得 handlers 写值进入response 对象。
//server.go - showing relevant code package http type response struct { ... //methods of ResponseWriter implemented by response func (w *response) Header() Header {... func (w *response) WriteHeader(code int) {... //readRequest returns a pointer to the response func ... readRequest(..) (w *response, err error) { return &response{...} } //serves the request func (c *conn) serve(ctx context.Context) { w_ptr, _ = readRequest(...) ... handler.ServeHTTP(w_ptr)
所以通常看来,即便 interface 可以被传值,更多的时候,它被作为指针来传递。
总结:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。