⼀、变量
(⼀)、变量的概念
变量是计算机语⾔中储存数据的抽象概念。变量的功能是存储数据。变量
通过变量名访问;
变量的本质是计算机分配的⼀⼩块内存,专⻔⽤于存放指定数据,在程序
运⾏过程中该数值可以发⽣改变;
变量的存储往往具有瞬时性,或者说是临时存储,当程序运⾏结束,存放
该数据的内存就会释放,⽽该变量就会消失;
Go 语⾔的变量名由字⺟、数字、下划线组成,⾸个字符不能为数字;
Go语法规定,定义的局部变量若没有被调⽤则编译错误。
命名 : camelCasing⻛格,不建议⽤下划线连接多个单词。
(⼆)、声明变量
变量声明有多种形式
1、未初始化的标准格式
var 变量名 变量类型
2、未初始化的批量格式
Go语⾔基本语法——变量及常量
不⽤每⾏都⽤var申明
var (
a int
b string
c []float32
d func() bool
e struct {
x int
y string
}
)
未初始化变量的默认值:
整形和浮点型变量默认值:0
字符串默认值为空字符串
布尔型默认值为false
函数、指针变量初始值为nil
3、初始化变量的标准格式
var 变量名 类型 = 表达式
4、初始化变量的编译器⾃动推断类型格式
var 变量名 = 表达式
5、初始化变量的简短声明格式(短变量声明格式)
变量名 := 表达式
使⽤ := 赋值操作符,:= 可以⾼效地创建⼀个新的变量,称之为初始化声
明。
声明语句省略了var 关键字
变量类型将由编译器⾃动推断
这是声明变量的⾸选形式,但是它只能被⽤在函数体内,⽽不可以⽤于全
局变量的声明与赋值
该变量名必须是没有定义过的变量,若定义过,将发⽣编译错误
在多个短变量声明和赋值中,⾄少有⼀个新声明的变量出现在左侧中,那
么即便有其它变量名可能是重复声明的,编译器也不会报错。
(三)、变量多重赋值(多个变量同时赋值)
Go语法中,变量初始化和变量赋值是两个不同的概念。Go语⾔的变量赋
值与其他语⾔⼀样,但是Go提供了其他程序员期待已久的多重赋值功能,
可以实现变量交换。多重赋值让Go语⾔⽐其他语⾔减少了代码量。
(四)、匿名变量
Go语⾔的函数可以返回多个值,⽽事实上我们并不是对所有的返回值都
⽤得上。那么就可以使⽤匿名变量,⽤“_”下划线替换即可。
匿名变量不占⽤命名空间,不会分配内存。
⼆、数据类型
基本数据类型(原⽣数据类型):整型、浮点型、布尔型、字符串、字节
byte和字符rune
复合数据类型(派⽣数据类型):指针(pointer)、数组(array)、切
⽚(slice)、映射(map)、函数(function)、结构体(struct)、通道
(channel)
(⼀)、整型
整型分两⼤类
按⻓度分:int8、int16、int32、int64、int
⽆符号整型:uint8、uint16、uint32、uint64、uint
其中uint8就是byte型,int16对应C语⾔的short型,int64对应C语⾔
的long型。
序号 | 类型和描述 |
1 | uint8 ⽆符号 8 位整型 (0 到 255) 【2的8次⽅】 |
2 | uint16 ⽆符号 16 位整型 (0 到 65535) 【2的16次⽅】 |
3 | uint32 ⽆符号 32 位整型 (0 到 4294967295) 【2的32次⽅】 |
4 | uint64 ⽆符号 64 位整型 (0 到 18446744073709551615) 【2的64次⽅】 |
5 | int8 有符号 8 位整型 (-128 到 127) |
6 | int16 |
序号 | 类型和描述 |
1 | byte 类似 uint8 |
2 | rune 类似 int32 |
3 | uint 32 或 64 位 |
4 | int 与 uint ⼀样⼤⼩ |
5 | uintptr ⽆符号整型,⽤于存放⼀个指针 |
(⼆)、浮点型
Go语⾔⽀持4种浮点型数:float32、float64、complex64(32 位实数和
虚数)、complex128(64 位实数和虚数)
float32的最⼤范围是3.4e38,⽤常量定义是:math.MaxFloat32
float64的最⼤范围是1.8e308,⽤常量定义是:math.MaxFloat64
(三)、布尔型
声明⽅式:var flag bool
布尔型⽆法参与数值运算,也⽆法与其他类型进⾏转换。
(四)、字符串
字符串在Go语⾔中是以基本数据类型出现的,使⽤字符串就像使⽤其他
序号 类型和描述
1 uint8
⽆符号 8 位整型 (0 到 255) 【2的8次⽅】
2 uint16
⽆符号 16 位整型 (0 到 65535) 【2的16次⽅】
3 uint32
⽆符号 32 位整型 (0 到 4294967295) 【2的32次⽅】
4 uint64
⽆符号 64 位整型 (0 到 18446744073709551615) 【2的64次⽅】
5 int8
有符号 8 位整型 (-128 到 127)
6 int16
有符号 16 位整型 (-32768 到 32767)
7 int32
有符号 32 位整型 (-2147483648 到 2147483647)
8 int64
有符号 64 位整型 (-9223372036854775808 到 9223372036854775807)
序号 类型和描述
1 byte
类似 uint8
2 rune
类似 int32
3 uint
32 或 64 位
4 int
与 uint ⼀样⼤⼩
5 uintptr
⽆符号整型,⽤于存放⼀个指针
原⽣基本数据类型int、float32、float64、bool⼀样。
字符串中可以使⽤转移符
\r 回⻋符return,返回⾏⾸
\n 换⾏符new line,直接跳到下⼀⾏的同列位置
\t 制表符TAB
\' 单引号
\" 双引号
\\ 反斜杠
定义多⾏字符串
双引号书写字符串被称为字符串字⾯量(string literal),这种字⾯
量不能跨⾏;
多⾏字符串需要使⽤“`”反引号,多⽤于内嵌源码和内嵌数据;
在反引号中的所有代码不会被编译器识别,⽽只是作为字符串的⼀部
分。
(五)、字符
字符串中的每⼀个元素叫做“字符”,定义字符时使⽤单引号。Go语⾔的字
符有两种:
1、byte型:其实是uint8的别名。代表了⼀个ASCII码的⼀个字符
2、rune型:其实就是int32。代表⼀个UTF-8字符。当需要处理中⽂等
unicode字符集时需要⽤到rune类型。
var a byte = 'a'
var b rune = '⼀'
三、打印格式化
(⼀)、通⽤
%v 值的默认格式表示 value
%+v 类似%v,但输出结构体时会添加字段名
%#v 值的Go语法表示
%T 值的类型的Go语法表示 type
(⼆)、布尔值
%t 单词true或false true
(三)整数
%b 表示为⼆进制 binary
%c 该值对应的unicode码值 char
%d 表示为⼗进制 digital
%8d 表示该整型⻓度是8,不⾜8则在数值前补空格。如果超出8,则以
实际为准。
%08d 数字⻓度是8,不⾜8位的,在数字前补0。如果超出8,则以实际
为准。
%o 表示为⼋进制 octal
%q 该值对应的单引号括起来的go语法字符字⾯值,必要时会采⽤安
全的转义表示 quotation
%x 表示为⼗六进制,使⽤a-f hex
%X 表示为⼗六进制,使⽤A-F
%U 表示为Unicode格式:U+1234,等价于"U+%04X" unicode
(四)、浮点数与复数的两个组分
%b ⽆⼩数部分、⼆进制指数的科学计数法,如-123456p-78;参⻅
strconv.FormatFloat
%e (=%.6e)有6位⼩数部分的科学计数法,如-1234.456e+78
%E 科学计数法,如-1234.456E+78
%f (=%.6f)有6位⼩数部分,如123.456123 float
%F 等价于%f
%g 根据实际情况采⽤%e或%f格式(以获得更简洁、准确的输出)
%G 根据实际情况采⽤%E或%F格式(以获得更简洁、准确的输出)
(五)、字符串和[]byte
%s 直接输出字符串或者[]byte string
%q 该值对应的双引号括起来的go语法字符串字⾯值,必要时会采⽤
安全的转义表示
%x 每个字节⽤两字符⼗六进制数表示(使⽤a-f)
%X 每个字节⽤两字符⼗六进制数表示(使⽤A-F)
(六)、指针
%p 表示为⼗六进制,并加上前导的0x pointer
没有%u。整数如果是⽆符号类型⾃然输出也是⽆符号的。类似的,也没
有必要指定操作数的尺⼨(int8,int64)。
宽度通过⼀个紧跟在百分号后⾯的⼗进制数指定,如果未指定宽度,则表
示值时除必需之外不作填充。精度通过(可选的)宽度后跟点号后跟的⼗进
制数指定。如果未指定精度,会使⽤默认精度;如果点号后没有跟数字,表
示精度为0。举例如下:
%f: 默认宽度,默认精度
%9f 宽度9,默认精度
%.2f 默认宽度,精度2
%9.2f 宽度9,精度2
%9.f 宽度9,精度0
(七)、其它flag
'+' 总是输出数值的正负号;对%q(%+q)会⽣成全部是ASCII字符的
输出(通过转义);
' ' 对数值,正数前加空格⽽负数前加负号;
'-' 在输出右边填充空⽩⽽不是默认的左边(即从默认的右对⻬切换为左对
⻬);
'#' 切换格式:
⼋进制数前加0(%#o),⼗六进制数前加0x(%#x)或0X(%#X),
指针去掉前⾯的0x(%#p);
对%q(%#q),如果strconv.CanBackquote返回真会输出反引号括起
来的未转义字符串;
对%U(%#U),输出Unicode格式后,如字符可打印,还会输出空格
和单引号括起来的go字⾯值;
对字符串采⽤%x或%X时(% x或% X)会给各打印的字节之间加空格;
'0' 使⽤0⽽不是空格填充,对于数值类型会把填充的0放在正负号后
⾯;
四、数据类型转换
(⼀)、数据类型转换的格式
1、T(表达式)
采⽤数据类型前置加括号的⽅式进⾏类型转换。T表示要转换的类型;表
达式包括变量、数值、函数返回值等。
类型转换时,需要考虑两种类型之间的关系和范围,是否会发⽣数值截
断。
布尔型⽆法与其他类型进⾏转换。
2、float与int之间转换
需要注意float转int时精度的损失
3、int转string
其实相当于是byte或rune转string。
该int数值是ASCII码的编号或Unicode字符集的编号。转成string就是将根
据字符集,将对应编号的字符查找出来。
当该数值超出Unicode编号范围,则转成的字符串显示为乱码。
例如19968转string,就是“⼀”。
【备注:】
ASCII字符集中数字的10进制范围是[30 - 39]
ASCII字符集中⼤写字⺟的10进制范围是[65 - 90]
ASCII字符集中⼩写字⺟的10进制范围是[97 - 122]
Unicode字符集中汉字的范围是[4e00-9fa5],10进制范围是
[19968 - 40869]
4、string转int
不允许字符串转int(cannot convert 变量 (type string) to type int)
五、常量
(⼀)、声明⽅式
1、相对于变量,常量是恒定不变的值,例如圆周率。
常量是⼀个简单值的标识符,在程序运⾏时,不会被修改。
2、常量中的数据类型只可以是布尔型、数字型(整数型、浮点型和复数)和字
符串型。
3、常量的定义格式:
const 标识符 [类型] = 值
可以省略类型说明符 [type],因为编译器可以根据变量的值来⾃动推断其
类型。
显式类型定义: const B string = "Steven"
隐式类型定义: const C = "Steven"
4、多个相同类型的声明可以简写为:
const WIDTH , HEIGHT = value1, value2
5、常量定义后未被使⽤,不会在编译时出错。
(⼆)、常量⽤于枚举(常量组)
例如以下格式:
const (
Unknown = 0
Female = 1
Male = 2
)
数字 0、1 和 2 分别代表未知性别、⼥性和男性。
常量组中如果不指定类型和初始值,则与上⼀⾏⾮空常量的值相同。
const (
a = 10
b
c
)
打印a、b、c,输出:10 10 10
(三)、iota
1、iota,特殊常量值,是⼀个系统定义的可以被编译器修改的常量值。iota只能
⽤在常量赋值中。
2、在每⼀个const关键字出现时,被重置为0,然后每出现⼀个常量,iota所代
表的数值会⾃动增加1。iota可以理解成常量组中常量的计数器,不论该常量的值
是什么,只要有⼀个常量,那么iota就加1。
3、iota 可以被⽤作枚举值:
const (
a = iota
b = iota
c = iota
)
println(a, b, c)
打印输出:0 1 2
第⼀个 iota 等于 0,每当 iota 在新的⼀⾏被使⽤时,它的值都会⾃动加
1;所以 a=0, b=1, c=2
4、常量组中如果不指定类型和初始值,则与上⼀⾏⾮空常量的值相同。所以上
述的枚举可以简写为如下形式:
const (
a = iota
b
c
)
println(a, b, c)
打印输出:0 1 2
5、示例⼀
const (
i = 1<<iota
j = 3<<iota
k
l
)
func main() {
fmt.Println("i=",i)
fmt.Println("j=",j)
fmt.Println("k=",k)
fmt.Println("l=",l)
}
打印输出结果:
i= 1
j= 6
k= 12
l= 24
6、示例⼆
const (
a1 = '⼀'
b1
c1 = iota
d1
)
func main() {
fmt.Println(a1, b1, c1, d1)
}
打印输出结果:
19968 19968 2 3
六、类型别名(Type Alias)
(⼀)、概要
类型别名是Go1.9版本添加的新功能。主要⽤于代码升级、迁移中类型的兼容性
问题。
在Go1.9版本前内建类型定义的代码是:
type byte uint8
type rune int32
⽽在Go1.9版本之后变更为:
type byte = uint8
type rune = int32
(⼆)、类型别名与类型定义
1、类型别名的语法格式:
type 类型别名 = 类型
2、定义类型的语法格式:
type 新的类型名 类型
例如:
type NewString string
该语句是将NewString定义为string类型。通过type关键字,NewString会形
成⼀种新的类型。NewString本身依然具备string的特性。
type StringAlias = string
该语句是将StringAlias定义为string的⼀个别名。使⽤StringAlias与string等
效。别名类型只会在代码中存在,编译完成时,不会有别名类型。
(三)、⾮本地类型不能定义⽅法
不能为不在同⼀个包中的类型定义⽅法。
package main
improt "time"
七、出于性能考虑的最佳实践和建议
1. 尽可能的使⽤ := 去初始化声明⼀个变量(在函数内部);
2. 尽可能的使⽤字符代替字符串;
3. 尽可能的使⽤切⽚代替数组;
4. 尽可能的使⽤数组和切⽚代替map;
5. 如果只想获取切⽚中某项值,不需要值的索引,尽可能的使⽤for range去
遍历切⽚,这⽐必须查询切⽚中的每个元素要快⼀些;
6. 当数组元素是稀疏的(例如有很多0值或者空值nil),使⽤map会降低内
存消耗;
7. 初始化map时指定其容量;
8. 当定义⼀个⽅法时,使⽤指针类型作为⽅法的接收者;
9. 在代码中使⽤常量或者标志提取常量的值;
10. 尽可能在需要分配⼤量内存时使⽤缓存;
11. 使⽤缓存模板