在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
new和make方法是GO语言内建的两个方法,主要用来创建分配类型内存,但二者有些许不同: 变量声明:var i int var str string 通过var关键字声明变量,然后在程序中使用,我们不指定其默认值时,这些变量的默认值也是其零值,(PS:建议不要使用零值做一些特殊情况的判断,会对结果产生影响) 对于引用类型,默认值为nil,看一下下面一段代码: import ( "fmt" ) func main() { var i *int *i=10 fmt.Println(*i) } 结果会输出什么? 运行时会报panic,
对于引用类型的变量,我们不光要声明它,还要为它分配内容空间,否则我们的值放在哪里去呢?这就是上面错误提示的原因。PS:对于值类型的声明不需要,因为已默认分配好了。 还是原来的例子,添加 i = new(int)// The new built-in function allocates memory. The first argument is a type, // not a value, and the value returned is a pointer to a newly // allocated zero value of that type. func new(Type) *Type 它只接受一个参数,这个参数是一个类型,分配好内存后,返回一个指向该类型内存地址的指针。同时请注意它同时把分配的内存置为零,也就是类型的零值。 再看一个例子: func main() { u:=new(user) u.lock.Lock() u.name = "张三" u.lock.Unlock() fmt.Println(u) } type user struct { lock sync.Mutex name string age int } 示例中的 这就是 make
PS:因为这三种类型是引用类型,所以必须得初始化,但是不是置为零值,这个和 func make(t Type, size ...IntegerType) Type 二者异同: 二者都是内存的分配(堆上),但是
new这个内置函数其实不常用,new的作用是可以分配内存让我们使用。但现实中,我们直接使用短语句声明和结构体的初始化达到我们的目的,例如: x := 0 u := User{} PS:一般工程中的结构体命名建议使用大写,如TimeSlice,变量的声明使用单驼峰的写法,如timeSlice := TimeSlice{} 二、数组和SliceGo语言中数组是具有固定长度而且拥有零个或者多个相同数据类型元素的序列。数组长度固定,在Go语言中比较少直接使用。Slice长度可增可减,使用场合较多。 区别:(1)数组在使用的过程中都是值传递,将一个数组赋值给一个新变量或作为方法参数传递时,是将源数组在内存中完全复制了一份,而不是引用源数组在内存中的地址。 (2)每个Slice都是都源数组在内存中的地址的一个引用,源数组可以衍生出多个Slice。满足了内存空间的复用和数组元素的值的一致性的应用需求。 详细看一下1、数组中每个元素是按照索引来访问的,索引从0到数组长度减1。Go语言内置函数len()可以返回数组中的元素个数 // 初始化 var a [3] int //3个整数型的数组,初始值是3个0 arr:=[5]int{1,2,3,4,5} //长度为5 var array2 = [...]int{6, 7, 8} //不声明长度 q := [...] int {1,2,3} //不声明长度 r := [...] int {99:-1} //长度为100的数组,只有最后一个是-1,其他都是0 2、slice表示一个拥有相同类型元素的可变长度序列。 slice通常被写为[]T,其中元素的类型都是T;它看上去就像没有长度的数组类型。 数组和slice其实是紧密关联的。slice可以看成是一种轻量级的数据结构,可以用来访问数组的部分或者全部元素,而这个数组称之为slice的底层数组。 Slice有三个属性:指针,长度和容量。指针指向数组的第一个可以从slice中访问的元素,这个元素不一定是数组的第一个元素。长度指的是slice中的元素个数,不能超过slice的容量。指针通常是从指向数组的第一个可以从slice中访问的元素,这个元素不一定是数组的第一个元素。长度指的是slice中的元素个数,它不能超过slice的容量。容量的大小通常大于等于长度,会随着元素个数增多而动态变化。Go语言的内置函数len()和 cap()用来返回slice的长度和容量。 //初始化 s1 := []int{1, 2, 3} //注意与数组初始化的区别,在内存中构建一个包括有3个元素的数组, //然后将这个数组的应用赋值给s这个Slice a := [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0} //a是数组 s2 := a[2:8] //从数组中切片构建Slice s3 := make([]int, 10, 20) //make函数初始化,len=10,cap=20 len和cap关系在添加元素时,若cap容量不足时,cap一般扩容2倍。 注:Slice的扩容规则 // 如果新的大小是当前大小2倍以上,则直接扩容为这个新的cap; // 否则循环以下操作:如果当前大小小于1024,按每次2倍增长,否则每次按当前大小1/4增长。直到增长的大小超过或等于新cap。
三、无缓冲 Channel 和有缓冲 Channel首先,要了解一个概念: 阻塞:
我们创建Channel有两种方式:
c1:=make(chan int) 无缓冲 c2:=make(chan int,1) 有缓冲 无缓冲的 不仅仅是 向 c1 通道放 1 ,而是一直要有别的协程 <-c1 接手了 这个参数,那么c1<-1才会继续下去,要不然就一直阻塞着 而 c2<-1 则不会阻塞,因为缓冲大小是1 只有当 放第二个值的时候 第一个还没被人拿走,这时候才会阻塞。 无缓冲Channel是同步的,有缓冲Channel是非同步的 // channel 中自带缓冲区。创建时可以指定缓冲区的大小。 // w:直到缓冲区被填满后,写端才会阻塞。 // r:缓冲区被读空,读端才会阻塞。 // len:代表缓冲区中,剩余元素个数, // cap:代表缓冲区的容量。 // 在这里可以举个小小的例子来解释一下有缓冲channel和无缓冲channel // 同步通信: 数据发送端,和数据接收端,必须同时在线。 —— 无缓冲channel // 打电话。打电话只有等对方接收才会通,要不然只能阻塞 // 异步通信:数据发送端,发送完数据,立即返回。数据接收端有可能立即读取,也可能延迟处理。 —— 有缓冲channel 不用等对方接受,只需发送过去就行 缓冲 package main import ( "fmt" "time" ) func loop(ch chan int) { for { select { case i := <-ch: fmt.Println("this value of unbuffer channel", i) } } } func main() { ch := make(chan int,3) ch <- 1 ch <- 2 ch <- 3 ch <- 4 go loop(ch) time.Sleep(1 * time.Millisecond) }
|
请发表评论