变量
GO变量总是有固定的数值类型,类型决定了变量内存的长度和存储格式。我们只能修改变量,无法改变类型
编译后的机器码从不使用变量名,而是直接通过内存地址访问目标数据
定义
关键字 var 用于定义变量
var x int //自动初始化为0var y = false //自动推断为bool类型var x,y int
多变量赋值
var x,s = 100,"abc"var x,y = y+3,x+2
首先计算出所有右值,然后赋值
建议以组的方式定义变量
var( x , y int a , b = 100 ,'abc')
简短模式
x := 100a,b := 1,'abc'
简短模式限制:
定义变量,同时显示初始化
不能提供数据类型
只能用在函数内部
例:
package main var x = 100 //全局变量func main(){ println(&x,x) x:="abc" //重新定义和初始化同名局部变量 println(&x,x)}输出0x49a018 100 //对比内存地址0xc420039f68 abc
简短模式也可以退化赋值(变量内存地址不发生改变)
条件:最少有一个新变量被定义,且必须是同一作用域
编译器将未使用局部变量当作错误
命名
以字母或下划线开始,由多个字母,数字,下划线组成
空标识符
“_” 通常作为忽略占位符使用,无法读取其内容
常量 const
const x,y int = 123,0x22const c = '哦'
常量定义 右值不能超出常量类型取值范围,否则会溢出
常量可以是某些编译器能计算出结果的表达式
常量组不知定类型和初始值,则与上一行非空常量右值相同
例
const( x uint16 = 120 y s = "abc" z)
枚举
借助iota 标识符实现一组自增常量
const( x = iota //0 y //1 z //2)const( _,_ = iota,iota * 10 //0, 0*10 a,b //1, 1*10 c,d //2, 2*10)
中断iotaz自增
const( a = iota //0 b //1 c = 100 //100 d //100 e = iota //4 恢复iota自增 f //5)
自增默认数据类型 int 可显示指定类型
建议用自定义类型实现用途明确的枚举类型。但不能将取值范围限定在预定义的枚举内
数字常量不会分配存储空间。
基本类型
长度
bool byte uint8int,uint 32或64 依据平台int8,uint8 -128~127,0~255int16,uint16 -32768~32767,0~65535int32,uint32 -21亿~21亿,0~42亿int64,uint64 float32 float64complex64complex128rune Unicode Code Point,int32uintptr 足以存储指针的uintstringarray 数组struct 结构体function 函数interface 接口map 字典slice 切片channel 通道
标准库math 定义了各种数字类型的取值范围
标准库strconv 可在不同进制(字符串)间转换
例:
package mainimport "strconv"func main(){ a,_:=strconv.ParseInt("1100100",2,32) println (a) println("0b" + strconv.FormatInt(a,2))}输出1000b1100100
别名:
byte alias for uint8rune alias for int32
引用类型:特指 slice,map,channel
内置函数 new按指定类型长度分配零值内存,返回指针,并不关心类型内部构造和初始化方式
new 为引用分配内存,但创建不完整。
引用类型必须使用make函数创建
例:
package mainfunc mkslice() []int{ s := make([]int,0,10) s = append(s,100) return s}func mkmap() map[string]int { m := make(map[string]int) m["a"] = 1 return m}func main(){ m := mkmap() println(m["a"]) s := mkslice() println(s[0])}输出:1100
类型转换
除常量,别名类型以及未命名类型
GO强制要求使用显式类型转换
混合类型表达式必须确保类型一致
不能将非bool类型结果当作 true/false
如果转换目标是指针,单向通道或没有返回值的函数类型,那么必须使用括号
用括号,让编译器将*int解析为指针类型
(*int)(p) *(int(p))(<-chan int)(c) <-(chan int(c))(func())(x) func() x
自定义类型
使用type定义用户自定义类型
type flags byte
多个type定义可以合并成组
type( user struct{ name string age uint8 } event func(string) bool)
自定义类型只表明有相同的底层数据结构,属完全不同的两种类型
不会继承基础类型的其他信息(包括方法)不能视作别名,不能隐式转换,不能直接用于比较表达式
例:
type data intvar d data = 10var x int = d //错误
未命名类型
数组,切片,字典,通道灯类型与具体元素类型或长度等属性有关,故称作未未命名类型。也可以用type为其提供具体的名称,将其变为命名类型
具有相同声明的未命名类型称为同一类型
具有相同基类型的 指针
具有相同元素类型和长度的 数组(array)
具有相同元素类型 切片(slice)
具有相同键值类型 字典(map)
具有相同数据类型及操作方向 通道(channel)
具有形同字段序列(字段名,字段类型,标签,以及字段顺序)结构体(struct)
具有相同签名(参数和返回值列表,不包括参数名) 函数(func)
具有相同方法集(方法名,方法签名,不包括顺序) 接口(interface)
例:
var a struct{ x int 'x'}var b struct{ x int}b=a //错误
var a func(int,string)var b func(string,int)a=b //错误 参数顺序也属于签名
未命名类型转换规则
所属类型相同
基础类型相同,且其中一个是未命名类型
数据类型相同,将双向通道赋值給单向通道,且其中一个为未命名类型
将默认值 nil 赋值給切片,字典,通道,指针,函数或接口
对象实现了接口
例:
type data [2]intvar d data = [2]int{1,2} //基础类型相同,右为未命名类型
a:=make(chan int,2)var b chan <- int = a //双向通道转换为单向通道,b为未命名类型