Open jinhailang opened 6 years ago
指针和引用的使用场景关键在于两个字 延后,当我们需要延后修改 A 变量,可以先让变量 B 指向 A ,然后操作 B 就是操作 B 了。
延后
A
B
以下为伪代码:
B:=&A B=xxx
但是,golang 在赋值时,需要注意是引用还是拷贝,对于数组,切片,channel,map 默认是引用,即:
mp := make(map[string]string) mp["a"] = "aaa" mm := mp mm["a"] = "sbsb" mm["b"] = "hahahha" fmt.Printf("mp: %v", mp) // mp: map[a:sbsb b:hahahha]
但是,当 slice 使用 append 添加元素时需要额外注意,可能踩入一个著名的坑:
append
mp := make([]string, 1, 1) mp[0] = "aaa" mm := &mp mm = append(*mm, "sbsb") mm = append(*mm, "hahahha") fmt.Printf("mp: %v\r\n", mp) // mp: [aaa]
思考上面的代码,为什么 slice 变量 mp 里面值没有被修改呢?
mp
这是因为当使用 append,超过 slice 容量时,会自动重新分配内存大小(扩容),可能是 2 倍或 1/4 的扩容,具体自行研究。这里扩容后 mm 地址会改变,因此 mp 与 mm 指向的地址块也就不一样了。
mm
这种场景下,如何仍然保持 mm 和 mp 指向的地址一致呢?可以使用 引用,上面的代码作如下修改即可:
引用
mp := make([]string, 1, 1) mp[0] = "aaa" mm := &mp *mm = append(*mm, "sbsb") *mm = append(*mm, "hahahha") fmt.Printf("mp: %v\r\n", mp)
合理的使用指针和引用,才能写出更高效,优雅的代码。
思考如下问题:
flag 包是用来解析程序参数输入的,我们可以自定义解析函数,例如:
flag
package main import ( "flag" "fmt" "strings" ) type ary []string func (ar *ary) String() string { return fmt.Sprintf("%v", *ar) } func (ar *ary) Set(v string) error { fmt.Printf("v: %s\r\n", v) *ar = ary(strings.Split(v, ",")) return nil } func aryVar(name, value string, usage string) *ary { f := ary(strings.Split(value, ",")) flag.CommandLine.Var(&f, name, usage) return &f } func main() { temp := aryVar("g", "1", "spilt ,") flag.Parse() fmt.Printf("temp: %v\r\n", *temp) }
以上代码中为什么要使用引用,返回指针呢?
这块代码还是包括了接口的使用,仔细思考,受益颇多。
接口
指针和引用的使用场景关键在于两个字
延后
,当我们需要延后
修改A
变量,可以先让变量B
指向A
,然后操作B
就是操作B
了。以下为伪代码:
但是,golang 在赋值时,需要注意是引用还是拷贝,对于数组,切片,channel,map 默认是引用,即:
但是,当 slice 使用
append
添加元素时需要额外注意,可能踩入一个著名的坑:思考上面的代码,为什么 slice 变量
mp
里面值没有被修改呢?这是因为当使用 append,超过 slice 容量时,会自动重新分配内存大小(扩容),可能是 2 倍或 1/4 的扩容,具体自行研究。这里扩容后
mm
地址会改变,因此mp
与mm
指向的地址块也就不一样了。这种场景下,如何仍然保持
mm
和mp
指向的地址一致呢?可以使用引用
,上面的代码作如下修改即可:合理的使用指针和引用,才能写出更高效,优雅的代码。
思考如下问题:
flag
包是用来解析程序参数输入的,我们可以自定义解析函数,例如:以上代码中为什么要使用引用,返回指针呢?
这块代码还是包括了
接口
的使用,仔细思考,受益颇多。