Golang 问题点(一)

董小贱 · 2020-02-27 07:32:41 · 729 次点击 · 预计阅读时间 3 分钟 · 大约8小时之前 开始浏览    
这是一个创建于 2020-02-27 07:32:41 的文章,其中的信息可能已经有所发展或是发生改变。

1. make和new的区别:

makenew都在堆上分配内存. 但是他们的行为不同, 适用于不同的类型.

new(T) 返回的是T的指针, 其中T为一个类型, 不是一个值, 为T类型新值分配内存空间并将此空间初始化为T类型的的零值, 返回的是新值得地址,即T的指针*T的值, 该指针指向T的新分配的零值.

make(T, args) 用来为slice,map货channel类型分配内存和初始化一个对象, 返回类型的引用we不是指针, 返回值根据T的不同而不同.

简单来讲: new 的作用是初始化一个指向类型的指针(*T),make 的作用是为 slice,map 或 chan 初始化并返回引用(T)

testNew := new([2]int)
 fmt.Println(testNew) //返回 &[0 0]
 (*testNew)[0] = 123
 fmt.Println(testNew) // 返回: &[123 0]


 testMake := make([]int, 3, 5)
 fmt.Println(testMake) // 返回 [0 0 0]
 testMake[0] = 1
 fmt.Println(testMake) // [2 0 0]

2. golang中的单引号 双引号和反引号:

双引号 用来创建可即系的字符串面量(支持转义, 但不能用来引用多行);

反引号 用来创建原生的字符串面量, 这些字符串可能有多行组成(不支持任何转义序列,比如\t, \n,这些都是字符串), 原生的字符串面量多用于书写多行消息, html以及正则表达式;

单引号 是Golang中一种特殊的类型:rune, 指的是: 码点字面量, 不做任何转义的字面内容.Golang中单引号的类型是int32. 所以,单引号中只能有一个字符.且多用[]rune来处理中文字符.

 
 a := 's'
 fmt.Printf("%v, %T\n", a, a)  // 115, int32
 b := "s"
 fmt.Printf("%v, %T\n", b, b) // s, string
 c := `s`
 fmt.Printf("%v, %T\n", c, c) // s, string

字符串的基本处理:

func backQuote(){
 testStr := `董小贱的简书`
 fmt.Println(len(testStr))
 fmt.Println(utf8.RuneCountInString(testStr))
 fmt.Println(testStr[:10])
 testRune := []rune(testStr)
 fmt.Println(testRune)
 fmt.Println(string(testRune[:2]))
 for i:=0; i<len(testRune); i++{
     fmt.Println(string(testRune[i]))
 }

}

func doubleQuote(){
 testStr := "董小贱的简书"
 fmt.Println(len(testStr))
 fmt.Println(utf8.RuneCountInString(testStr))
 fmt.Println(testStr[:10])
 testRune := []rune(testStr)
 fmt.Println(testRune)
 fmt.Println(string(testRune[:2]))
 for i:=0; i<len(testRune); i++{
     fmt.Println(string(testRune[i]))
 }
}

以上的数据大致相同, 唯一的区别是, 遍历字符串的时候,需要转换成[]rune类型, 遍历之后再准换成string类型才可以.需要注意的是:对\t等转义字符的处理, 在单引号中\t等转义字符被当做字符串对待, 不进行转义处理, 而在双引号中, \t会被转义处理. len(str)的数据跟[]rune(str)转换后的数据差三倍(都是中文的情况下)原因: Go中string底层是通过byte数组实现的. 中文字符在unicode下占两个字节, 在utf-8编码下占三个字节. golang默认编码是utf-8. byte是指的uint8, rune是指的int32

3. Go语言切片的三种状态: 零切片、空切片和nil切片

零切片: 表示底层数组的二进制内容都是0. 即对应的类型的零值。(即:make之后,长度和容量不为0的切片).

  testSlice := make([]int, 7, 9)
   fmt.Println(testSlice)
 
 // 结果:[0 0 0 0 0 0 0] 
 

大概的状态就是:


零切片.png

nil切片: 没有使用make进行激活的切片. 与nil比较为true, 可以通过append进行扩容。

    var testSlice []int
    var testSlice2 = *(new([]int))

    fmt.Println(len(testSlice), cap(testSlice))
    fmt.Println(len(testSlice2), cap(testSlice2))
    fmt.Println(testSlice == nil) // true
    fmt.Println(testSlice2 == nil) // true

空切片:已经激活,但是其长度和容量都为0, 与nil比较为false。可以通过append进行扩容。


    var testSlice = make([]int, 0)
    var testSlice2 = []int{}

    fmt.Println(len(testSlice), cap(testSlice)) // 0 0
    fmt.Println(len(testSlice2), cap(testSlice2)) // 0  0

    fmt.Println(testSlice == nil) // false
    fmt.Println(testSlice2 == nil) // false


One more thing....

切片的类型是一个结构体,将结构体的数据转换成数组类型,如下:

nil切片

var testSlice []int
testSlice2 := *(new([]int))
fmt.Println(*(*[3]int)(unsafe.Pointer(&testSlice))) // [0 0 0]
fmt.Println(*(*[3]int)(unsafe.Pointer(&testSlice2))) // [0 0 0]

可以看出nil切片的示意图如下:

001.png

零切片


    testSlice := make([]int,0)
    testSlice2 := []int{}
    fmt.Println(*(*[3]int)(unsafe.Pointer(&testSlice)))  // [824634167032 0 0]
    fmt.Println(*(*[3]int)(unsafe.Pointer(&testSlice2))) // [824634167032 0 0]

name零切片的示意图为:其地址都指向一个全局变量 zerobase 这里不展开

002.png

参考资料:http://www.meirixz.com/archives/80658.html


有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:董小贱

查看原文:Golang 问题点(一)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

729 次点击  
加入收藏 微博
下一篇:假期笔记
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传