Go圣经-学习笔记之复合类型


声明:本文转载自https://my.oschina.net/u/3287304/blog/1554921,转载目的在于传递更多信息,仅供学习交流之用。如有侵权行为,请联系我,我会及时删除。

上一篇 Go圣经-临时插入ORM的小trick

数组

数组是一个固定长度类型的序列,由零个或者多个同构元素组成。Go语言很少直接使用数组,一般使用Slice多。数组的表现形式:

var q [3]int =[3]int{1,2,3} var r [3]int =[3]int{1,2} var s =[...]int{1,2,3} 

数组类型是由类型和长度组成的。因此[3]int和[5]int是两个不同的数据类型

如果相同数组的元素类型是可以比较的,则这个数组是可以比较的。我们可以通过==进行数组比较。注意:这里不是C++,a==b,不是指针比较,而是数组所有元素的比较

我们如何比较两个动态数组是否相等呢?有两种方法:

  • 第一种,比较slice的len、cap和底层数组元素
  • 第二种,我们可以对slice序列化成byte流,然后利用sha256生成消息摘要, 摘要是32个字节的数组类型。然后直接比较即可。
func compareSlice(a []int, b []int) bool{     if len(a) != len(b) {         return false     }     for i:=0 ;i<len(a); i++{         if a[i]!=b[i]{             return false         }     }     return true } 

这里有必要提一下,为啥判断a和b相等, 不比较cap(a)与cap(b)的大小关系呢?是不是比较时,只比较数据呢?

注意:不用比较slice的底层数组指针所指向的内存地址, 数据存放肯定不在一起的。

package main  import ( 	"crypto/sha256" 	"fmt" )  func main() {     c1 := sha256.Sum256([]byte("x"))     c2 := sha256.Sum256([]byte("x"))     fmt.Printf("%x\n%x\n%t\n%T\n", c1, c2, c1 == c2, c1)     // Output:     // 2d711642b726b04401627ca9fbac32f5c8530fb1903cc4db02258717921a4881     // 2d711642b726b04401627ca9fbac32f5c8530fb1903cc4db02258717921a4881     // true     // [32]uint8 } 

当调用函数时,调用参数将会被赋值给函数内部的参数变量,所以函数参数接收是一个变量的副本,并不是原始的变量。Go语言的数据传递全部是值类型。所以数组传递是低效的,并且对数组的修改都是发生在拷贝的数组上,对传入的实参没有任何影响。若是C++等其他语言,则数组传递时,是传递的指针。同时附带数组的长度信息。如果一定要传数组,请传数组指针,例如func(aptr *[32]byte)。

Slice动态数组

一个很形象的例子

months := []string{1: "January", /* ... */, 12: "December"}

月份动态数组

这里有个我很懵逼的问题:

var months = []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}  // 夏天 summer:=months[6:9]  fmt.Println(summer[:20]) // slice超出了cap(summer),直接panic。  明白,因为summer容量是12-6=6  fmt.Println(summer[:6]) // [ 7,8,9,10,11,12 ] ,这里有点懵逼,其实summer[:6]已经超出len(summer)了,我觉得应该是有越界控制的,但是没有  var months = make([]int, 0, 12) fmt.Println(months[:10]) // [ 0,0,0,0,0,0,0,0,0,0 ] months[0] = 1 // panic: index out of range 

主要懵逼的问题:

  • 当读取slice动态数组时,只要读取范围不超过cap容量就ok了
  • 当写入slice动态数组时,只要超出len长度了,就报"index out of range"的panic

我的问题是,为什么不做一致性呢?读写都控制在len范围内呢?

利用slice动态数组,左旋转slice的前N个元素

package main  import "fmt"  func reverse(s []int) {     for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {         s[i], s[j] = s[j], s[i]     } }  func reverseN(s []int, n int) {     reverse(s[:n]) // 反转前N个数     reverse(s[n:]) // 反转后len(s)-n-1     reverse(s) }  func main() {     var a = []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}     var n = 5 // 指定旋转前N个数     reverseN(a, n)     fmt.Println(a)  // [5 6 7 8 9 10 11 12 0 1 2 3 4] } 

slice的比较问题

和数组不同的是,slice动态数组不能直接比较,不过标准库提供了bytes.Equal方法判断两个字节型slice是否相等。对于其他我们需要比较slice的元素个数和元素值。同时我们又引出struct类型的比较。

type Person struct {     Cap int     Len int     Bt  *byte }  func main() {     p1 := Person{         Cap: 28,         Len: 28,         Bt:  new(byte),     }     p2 := Person{         Cap: 28,         Len: 28,         Bt:  new(byte),     }     fmt.Println(p1 == p2) } 

上面这个DEMO是可以编译通过,且运行没有问题的,返回false。

但是slice的底层结构和这个是类似的。但是它不能比较,slice是一个特殊类型。尽量少的考虑它是一个struct类型。同时struct能够进行比较,取决于内部的各个元素是否能够比较。

那为什么不直接slice动态数组比较呢?只需要比较元素个数和每个元素比较。我们从《Go圣经-学习笔记入门bufio》, 的bytes.ReadSlice方法就可以知道line可能是间接引用的,它底层的数据可能会随时发生变化。这样比较的话是没有意义的,所以安全的做法是直接禁止slice比较。

本文发表于2017年10月23日 18:39
(c)注:本文转载自https://my.oschina.net/u/3287304/blog/1554921,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如有侵权行为,请联系我们,我们会及时删除.

阅读 1816 讨论 0 喜欢 0

抢先体验

扫码体验
趣味小程序
文字表情生成器

闪念胶囊

你要过得好哇,这样我才能恨你啊,你要是过得不好,我都不知道该恨你还是拥抱你啊。

直抵黄龙府,与诸君痛饮尔。

那时陪伴我的人啊,你们如今在何方。

不出意外的话,我们再也不会见了,祝你前程似锦。

这世界真好,吃野东西也要留出这条命来看看

快捷链接
网站地图
提交友链
Copyright © 2016 - 2021 Cion.
All Rights Reserved.
京ICP备2021004668号-1