你不知道的Golang盲点汇总【持续更新】
1. 引用传递时append会复制生成新的指针
package main
import ( "fmt" ) func w(s []int )[]int{ fmt.Printf("in w %v %#v ",s ,&s[] )
//append后s指定新复制的内存指针了,不再指向原来的内存
s=append(s, )
fmt.Printf("after append w %v %#v ",s ,&s[] )
return s
} func main() {
s:=[]int{}
fmt.Printf("out of w %v %#v ",s ,&s[] )
s2:=w(s)
//原来的指针s的内容依然在内存中,而不是被覆盖/GC了
fmt.Printf("after w %v %#v %v %#v ",s ,&s[],s2 ,&s2[] )
}
output:
out of w [] (*int)(0x40e020) in w [] (*int)(0x40e020) after append w [ ] (*int)(0x40e040) after w [] (*int)(0x40e020) [ ] (*int)(0x40e040)
2. 空值append
package main import (
"fmt"
) func main() {
s:=[][]int{}
//使用...更加方便,还不会导致塞入空值
fmt.Println("Hello, playground", append(s, [][]int{}... ), append(s, []int{} ))
}
output:
Hello, playground [] [[]]
3. 数组、slice、切片的雷!
package main import (
"fmt"
"reflect"
) func main() {
//固定长度是array类型,可以覆盖成员,但不能修改长度,即不能append
a := []int{,}
a[]=
//没设置长度是slice类型,即动态或不定长数组, 也能覆盖成员,也修改长度,即支持append
s := []int{,}
//s[1:len(s):cap(s)] 等效 s[1:len(s)]
s[]=
//注意下村是:左开(含左边元素),右闭(不含右边元素)
fmt.Printf("%#v %#v %v %v %#v %#v %#v \n", a ,s, reflect.TypeOf(a).Kind(), reflect.TypeOf(s).Kind(), a[:len(a)], s[:len(s):cap(s)],s[:len(s)], ) //subslice切片
//切片,也叫subslice,是一块基于父slice的投影
subArray:=a[:]
//报错:invalid slice index: 3 > 2, 即len不能超过cap
//subArray2:=subArray[0:3:2]
subArray2:=subArray[::]
//报错:index out of range [1] with length 1
//subArray2[1]=222
//报错:index out of range [1] with length 1,len+offset>父slice的cap ,投影不能超出父slice的cap区域
//subArray3:=subArray2[1:2:2]
subArray3:=subArray2[:]
//切片是指定父slice的指针,所以会修改父slice,使用时一定要小心!!!
subArray3[]= //subArray虽然是新变量名,但实际指定同一个内存地址
fmt.Printf("subslice %#v %#v %#v %#v %v %v %v %v\n", subArray, a, subArray2,subArray3, &subArray[], &a[], &subArray2[],&subArray3[]) //扩容测试
fmt.Printf("%v %v \n", len(s), cap(s))
s=append(s, )
fmt.Printf("%v %v \n", len(s), cap(s))
s=append(s, )
fmt.Printf("%v %v \n", len(s), cap(s))
//tmp:=[8]int{}
//错误:cannot use tmp (type [8]int) as type []int in append
//正确玩法:
//不能用Printf中有unicode,否则会 format %扩 has unknown verb 扩
fmt.Println("len增加且超过cap时,若<=1024,以100%扩容 ")
s=[]int{}
i:=
for i>= {
fmt.Printf("%v %v \n", len(s), cap(s))
s=append(s,)
i-=
} fmt.Println("len增加且超过cap>1024时,否则以大约25%扩容,注意是大约")
//大约25%扩容详细参考: https://juejin.im/post/5ca4239ef265da30807fea48
i=
s=[]int{}
for i>= {
s=append(s,)
i-=
if i%=={
fmt.Printf("%v %v \n", len(s), cap(s))
}
} }
output:
[]int{, , , } []int{, } array slice []int{, , } []int{} []int{}
subslice []int{, } []int{, , , } []int{} []int{} 0x40e020 0x40e020 0x40e020 0x40e020 len增加且超过cap时,若<=,以100%扩容 len增加且超过cap>1024时,否则以大约25%扩容,注意是大约
4. 字符串不能随意for
package main import (
"fmt"
) func main() {
s:="abc中国人" fmt.Println("for len是逐个unicode,也叫rune")
for k,v:=range s {
fmt.Println(k, string(v))
}
fmt.Println("for len是逐个字节, 非ascii就会乱")
for i:=;i<len(s);i++{
fmt.Println(i, string(s[i]))
}
fmt.Println("正确用法:")
//for len是逐个字节
u:=[]rune(s)
l:=len(u)
for i:=;i<l;i++{
fmt.Println(i, string(u[i]))
}
}
output:
for len是逐个unicode,也叫rune
a
b
c
中
国
人
for len是逐个字节, 非ascii就会乱
a
b
c
ä
¸
å
½
ä
º
º
正确用法:
a
b
c
中
国
人
4. map是无序的
package main import (
"fmt"
) func main() {
m:=map[string]string{
"cc":"CC",
"aa":"AA",
"bb":"BB",
}
for k,v:=range(m){
fmt.Println(k,v)
}
fmt.Println("")
for k,v:=range(m){
fmt.Println(k,v)
}
fmt.Println("")
for k,v:=range(m){
fmt.Println(k,v)
}
fmt.Println("")
// sort 'string' key in increasing order
fmt.Println("fix : ")
for k,v:=range(m){
fmt.Println(k,v)
} }
output:
cc CC
aa AA
bb BB cc CC
aa AA
bb BB bb BB
cc CC
aa AA fix :
cc CC
aa AA
bb BB
原因:
根据Go规范, map上的迭代顺序是不确定的,并且在程序运行之间可能会有所不同。实际上,不仅它是不确定的,而且实际上是有意随机化的。这是因为它曾经是可预测的,并且Go语言开发人员不希望人们依赖未指定的行为,所以他们有意地将其随机化,因此不可能依赖此行为。维护原插入顺序需要更多内存和cpu操作,Go设计简洁,无序意味着性能更佳,且不是所有地方都需要顺序。想排序或者按插入顺序,很容易自行实现。在Go 1.12+中,您只需打印一个map,它将自动按键排序。之所以添加它,是因为它可以轻松测试map。
原文:https://blog.golang.org/go-maps-in-action 中 When iterating over a map with a range loop, the iteration order is not specified and is not guaranteed to be the same from one iteration to the next. If you require a stable iteration order you must maintain a separate data structure that specifies that order。
解决:package mainimport ( "fmt" "sort"
)
//按插入的顺序
type RawSortedMap struct {
//map key类型不能是slices, maps, and functions; these types cannot be compared using==
, and may not be used as map keys.
m map[string]interface{}
keys []interface{}
} func NewRawSortedMap(cap int)RawSortedMap{
m := make(map[string]interface{}, cap)
keys:=make([]interface{}, cap)
n:=RawSortedMap{m, keys}
return n
} func (r *RawSortedMap) Set(k string, v interface{}) {
//通过k 快速查找
//map不能同时read 和write,否则请加sync.RWMutex锁或者CAS .
r.m[k] = len(r.m)
//通过keys数组快速遍历
r.keys = append(r.keys, v)
}
func main() { m := make(map[int]string)
m[] = "a"
m[] = "c"
m[] = "b" // To store the keys in slice in sorted order
var keys []int
for k := range m {
keys = append(keys, k)
}
//按数字大小的顺序
sort.Ints(keys)
//按字母的顺序
//sort.Strings(keys) // To perform the opertion you want
for _, k := range keys {
fmt.Println("Key:", k, "Value:", m[k])
}
}
你不知道的Golang盲点汇总【持续更新】的更多相关文章
- 《WCF技术剖析》博文系列汇总[持续更新中]
原文:<WCF技术剖析>博文系列汇总[持续更新中] 近半年以来,一直忙于我的第一本WCF专著<WCF技术剖析(卷1)>的写作,一直无暇管理自己的Blog.在<WCF技术剖 ...
- 中国.NET:各地微软技术俱乐部汇总(持续更新中...)
中国.NET:各地微软技术俱乐部汇总(持续更新中...) 本文是转载文,源地址: https://www.cnblogs.com/panchun/p/JLBList.html by 史记微软. ...
- redis日常使用汇总--持续更新
redis日常使用汇总--持续更新 工作中有较多用到redis的场景,尤其是触及性能优化的方面,传统的缓存策略在处理持久化和多服务间数据共享的问题总是不尽人意,此时引入redis,但redis是单线程 ...
- 跟我学SpringCloud | 终篇:文章汇总(持续更新)
SpringCloud系列教程 | 终篇:文章汇总(持续更新) 我为什么这些文章?一是巩固自己的知识,二是希望有更加开放和与人分享的心态,三是接受各位大神的批评指教,有任何问题可以联系我: inwsy ...
- 优步UBER司机全国各地最新奖励政策汇总(持续更新...)
滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://didi-uber.com/archiv ...
- 痞子衡嵌入式:史上最强i.MX RT学习资源汇总(持续更新中...)
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MX RT学习资源. 类别 资源 简介 官方汇总 i.MXRT产品主页 恩智浦官方i.MXRT产品主页,最权威的资料都在这里,参考手 ...
- IT书籍下载汇总--持续更新
本书单由北北分享,并持续更新,请将该地址加入收藏夹:北北的书单 .badge{float:right;}.list-group-item > .badge + .badge{margin-rig ...
- Type Script在Visual Studio 2013中的问题汇总(持续更新…)
TypeScript在vs2012下的问题 TypeScript对VS2012支持度比较低,建议升级为VS2013版本以上. 在VS2013中无法创建TypeScript项目 VS2013默认不支持T ...
- LeetCode All in One 题目讲解汇总(持续更新中...)
终于将LeetCode的免费题刷完了,真是漫长的第一遍啊,估计很多题都忘的差不多了,这次开个题目汇总贴,并附上每道题目的解题连接,方便之后查阅吧~ 477 Total Hamming Distance ...
随机推荐
- PlayJava Day001
今日所学: /* 2019.08.19开始学习,此为补档. */ 三目(元)运算符 格式:(表达式)? 表达式为true返回值A : 表达式为false返回值B 例: String s=2>3 ...
- Chrome浏览器Json查看插件JsonHandle下载以及无法安装插件的解决方法
场景 在使用Chrome浏览器查看Json数据时如果没有插件会挤作一团. 安装JsonHandle插件后 博客: https://blog.csdn.net/badao_liumang_qizhi 关 ...
- django9-ajax
1.ajax 局部刷新 ,不可能每次提交请求刷新整个页面 2.ajax实例 在不刷新整个的情况下完成计算器 ,ajax的post需要添加csrftoken 1)设置一个组件ajaxcsrf.html ...
- 2019年上半年收集到的人工智能LSTM干货文章
2019年上半年收集到的人工智能LSTM干货文章 门控神经网络:LSTM 和 GRU 简要说明 LSTM-CNN-Attention算法系列之一:LSTM提取时间特征 对时间序列分类的LSTM全卷积网 ...
- python函数修饰符@的使用
python函数修饰符@的作用是为现有函数增加额外的功能,常用于插入日志.性能测试.事务处理等等. 创建函数修饰符的规则:(1)修饰符是一个函数(2)修饰符取被修饰函数为参数(3)修饰符返回一个新函数 ...
- ABP进阶教程6 - 布局配置
点这里进入ABP进阶教程目录 解读参数 l - length changing input control (左上,每页显示记录数) f - filtering input (右上,过滤条件) t - ...
- 【cf741】D. Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths(dsu on tree)
传送门 题意: 给出一颗以\(1\)为根的有根树,树边带有一个字符(\(a\)~\(v\))的信息. 输出对于每个结点,其子树内最长的简单路径并且满足边上的字符能够组成回文串. 思路: 显然最终的答案 ...
- 初学JavaScript正则表达式(六)
JavaScript预定义类 ab+数字+任意字符 ab[0-9][^\r\n] 等价于 ab\d. '@123@abc@'.replace(/@./g,'Q') Q23Qbc@ 将"@加任 ...
- c# 第31节 构造函数与析构函数、new关键字作用
本节内容: 1:构造和析构的简介 2:构造函数的定义和使用 3:new关键字的作用 4:析构函数的定义和使用 1:构造和析构的简介 2:构造函数的定义和使用 构造函数: 当实例化的一个对象,就默认执行 ...
- Tensorflow之单变量线性回归问题的解决方法
跟着网易云课堂上面的免费公开课深度学习应用开发Tensorflow实践学习,学到线性回归这里感觉有很多需要总结,梳理记录下阶段性学习内容. 题目:通过生成人工数据集合,基于TensorFlow实现y= ...