一,slice特性
func main() {
var a map[string][]string = make(map[string][]string)
a["11"] = []string{"aa", "bb"}
var b map[string][]string = make(map[string][]string)
for k, info := range a {
b[k] = append(b[k], info...) //append 申请了一份内存并进行值拷贝
}
var c map[string][]string = make(map[string][]string)
for k, info := range a {
c[k] = info //c["11"]引用a["11"]的slice内存对象而已
}
a["11"][0] = "xx"
for k, v := range a {
fmt.Println(k, v)
}
for k, v := range b {
fmt.Println(k, v)
}
for k, v := range c {
fmt.Println(k, v)
}
}
打印:
11 [xx bb]
11 [aa bb]
11 [xx bb]
二,map特性
1,map赋值仅是赋值指针变量的赋值
var g_map map[key]value
并发访问map的技巧,定时更新map(定时指针赋值):在更新线程中,需要创建一个全新的map(注意这个map是在更新线程的函数栈中,对其它线程不可见),在更新线程中赋值完这个新map后,再使用该新map赋值给全局map:g_map = New_map;在赋值过程中(最多仅有三个指令),读线程要么读到老的g_map,要么读到新的new_map,因此不会有map并发的读写问题。
2,map赋值指针后,原正在被消费的指针所指的对象依然可用(不会崩溃)
var whiteDomainMp = make(map[string]map[string]bool)
func readMap() {
for {
for k, v := range whiteDomainMp {
time.Sleep(time.Second)
fmt.Printf("k:%s v:%+v\n", k, v)
for k1, v1 := range v {
fmt.Printf("k:%s v:%+v\n", k1, v1)
}
}
}
}
func main() {
whiteDomainMp["a"] = make(map[string]bool)
whiteDomainMp["a"]["aa"] = true
whiteDomainMp["b"] = make(map[string]bool)
whiteDomainMp["b"]["bb"] = true
whiteDomainMp["c"] = make(map[string]bool)
whiteDomainMp["c"]["cc"] = true
whiteDomainMp["d"] = make(map[string]bool)
whiteDomainMp["d"]["dd"] = true
go readMap()
for {
var tmp = make(map[string]map[string]bool)
tmp["a1"] = make(map[string]bool)
tmp["a1"]["aa1"] = true
tmp["b1"] = make(map[string]bool)
tmp["b1"]["bb1"] = true
tmp["c1"] = make(map[string]bool)
tmp["c1"]["cc1"] = true
tmp["d1"] = make(map[string]bool)
tmp["d1"]["dd1"] = true
time.Sleep(time.Duration(2) * time.Second)
whiteDomainMp = tmp
fmt.Printf("whiteDomainMp = tmp\n")
}
}
3,map不支持并发的读写,例如 var v map[key]value,不能并发的读写遍历key;即使key固定(不再新增或删除),也不能并发的读写value;测试代码:会导致map并发读写崩溃!
func readRoutine() {
for {
for k, p := range gMp {
fmt.Println(k, *p)
}
}
}
func writeRoutine() {
for {
for k, p := range gMp {
fmt.Println(*p)
new := fmt.Sprintf("%d", time.Now().Unix())
gMp[k] = &new
}
}
}
var gMp map[string]*string = make(map[string]*string)
func main() {
var a = "aaa"
gMp["a"] = &a
var b = "bbb"
gMp["b"] = &b
var c = "ccc"
gMp["c"] = &c
go readRoutine()
go writeRoutine()
go readRoutine()
go writeRoutine()
for {
}
}
三,接口的特性
接口类型可以关联不同类型的对象,以统一的方式调用不同对象的执行方法。例如下例 a、o 对象可以转成 lPrice 接口对象 i,调用 i.CalPrice() 会执行相应 a,o 对象类型的 CalPrice 方法。
type IPrice interface {
CalPrice(cnt int) int
}
type Apple struct {
Price int
Color string
}
type Orange struct {
Price int
weight int
}
func (a Apple) CalPrice(cnt int) int {
return cnt * a.Price
}
func (o Orange) CalPrice(cnt int) int {
return 3 + cnt * o.Price
}
func main() {
a := Apple{Price: 7}
o := Orange{Price: 4}
var iobj []IPrice
iobj = append(iobj, a, o)
for _, i := range iobj {
fmt.Println(i.CalPrice(3))
}
}