我的go语言完全是自学,所以将市面上所有能买到的golang书籍都买来看了。
基础都已研究完毕今天开始做总结,并且开始阅读go高级编程和进行实战演练。
go程序 4个主要声明 var、type、const、fun
包级别实体不仅对声明的包中可见,对同一个包所有源文件均可见。
变量声明
如 var name type = expression
其中类型和表达式可以忽略其中一个,但是不能全都忽略,忽略表达式则变量name的值为对应类型的零值,忽略type则name的类型根据表达式的类型来定。
类型零值
数字 0 , 布尔 false,字符串””,接口和引用类型 为nil
类型0值保证了go语言不存在未初始化代码。
短变量声明
用来声明和初始化局部变量。依赖一个明确的作用域。
格式:name := expression
name的类型由expression来定。
短变量声明不需要声明所有左边的变量,如果一些变量已经在词法块中声明,那么对于这些变量,短变量声明等同于赋值。
例:
a:=1
a,b:=2,3
注意短变量声明的作用就是表示声明,其中一个变量必须是未声明的才行,如果两个变量都在词法块中声明过就会报错。
指针
指针的值是变量存放的地址。不是所有的值都有地址,但是所有的变量都有。使用指针可以在无须知道变量名字的情况下,间接读取或者更新变量的值。
x:=1
p:=&x //p通过短变量声明为整形指针,指向x
*p = 2 //x = 2
每次使用变量的地址或者复制一个指针,我们就创建了新的别名或者方式来标记同一个变量,例如*p是x的别名,指针别名允许我们不用变量的名字来访问变量,不仅指针产生别名,当复制其他的引用类型包括含引用类型的结构体、数组、接口的值的时候,也会产生别名。
new()和make()的区别
两者都是在堆上分配内存,但是他们行为不同,适用于不同的类型。
new()用于值类型的内存分配,并置为0值。
make()只用于切片、字典、通道这三种引用数据类型的内存分配和初始化。这三种引用类型都拥有自己的结构需要初始化。new()并不初始化结构只是分配内存。
new(T)分配类型T的零值并返回地址,也就是指向类型T的指针。
mkae(T)返回类型T的值(不是*T)。
在go语言中并不能准确判断变量是在栈上还是在堆上分配。想知道变量分配的确切位置通过go build或者go run 时加上-m 的标志查看。
栈:存储函数中的局部变量,使用CPU管理的和优化,先进后出。
使用栈的优势不用你手动管理,读写速度也快。
堆:是计算机中一块内存区域,不会自动为你释放内存也不是CPU严格管理。在go语言中全部由垃圾回收算法自动决定。
变量的生命周期
指程序执行过程中变量存在的时间段。
包级别变量的声明周期是整个程序的执行时间。
局部变量的声明周期第动态的,每次执行声明语句创建一个新的实体,变量一直生存岛他变得不可能访问,这时他占用的存储空间被回收。
注意:局部变量是的生存时间是可以延续的,只要它的引用存在那这个变量就会一直存在(这里注意思考是否会影响程序效率增加内存负担后面会专门写)
func f()*int{
var x int
return &x
}
可赋值性
包含显式赋值和隐式赋值。
类型必须精准匹配,nil可以被赋值给任何接口变量或者引用类型。
类型声明
type定义一个新的命名类型。
type a float64 它的底层类型是float64,相同的底层类型可以进行显示的类型转换。
如: type b float 64 ,a(b)进行转换。
数字类型转换,字符串和一些slice类型间的转换是允许的。这些转换将会改变值的表达形式。例如从小数点转换为整型火丢失小数部分。
作用域
语法块是由大括号围起来的一个语句序列,把块的概念推广到其他没有显示包括在大括号中的声明代码,将其统称为词法块。一个声明的词法块决定声明的作用域大小。一个程序可以包含多个同名的声明,前提是他们都在不同的词法块。当编译器遇到一个名字的引用时,将从最内层的封闭词法块到全局块中寻找声明。
for循环创建两个词法块,一个显式的一个隐式的。
x := “hello”
for _,x = range x{ //隐式块
//显式块
}
if和switch也会创建隐式块
if x:=f(); x==0{
}else{
}
switch同理条件对应一个块,每个case语句对应一个块。
swith num:=3 ;num{
case 1:
……
fallthrough //继续向下执行但不在匹配条件表达式
case 2:
……
default:
……
}
类型转换
a:=10
b:=byte(a) // int转byte
c:= a + int(b) //混合类型表达式必须确保类型一致
不能将非bool类型当做true/false使用
如果要转换的类型是引用类型必须使用括号以避免语法分解错误
x:=100
p:=*int(x) //错误
正确
p:=(*int)(x)
( (func())(b) (func()int)(h) 未命名类型 与具有明确标识符的bool、int、string等类型相比,数组、切片、字典、通道等类型与具体元素类型或长度等属性有关,故乘坐为命名类型。可用type为其提供具体名称,为其改变为命名类型。 具有相同声明的为命名类型被视为同一类型。 具有相同基类型的指针。 具有相同元素类型和长度的数组。 具有相同元素类型的切片。 具有相同键值类型的字典。 具有相同数据类型及操作方向的通道。 具有相同字段的序列(字段名、字段类型、标签、字段顺序)的结构体。 具有相同签名的函数。 具有相同方法集的接口。