基本程序结构
package main//包,表明代码所在的模块
import "fmt"//引入代码依赖
//功能实现
func main() {
fmt.Println("Hello, GoLang!")
}
应用程序入口
- 必须是main包:package main
- 必须是main方法:func main()
- 文件名不一定是main.go
- 与其他主要编程语言的差异
- Go中的main函数不支持任何返回值,只能通过os.Exit来返回状态
- main函数不支持传入参数,在程序中直接通过os.Args获取命令行参数
编写测试程序
- 源码文件以_test结尾:xxx_test.go
- 测试方式以Test开头:func TestXXX(t *testing.T){...}
package try_test
import "testing"
func TestFirstTry(t *testing.T) {
t.Log("My first try!")
}
变量赋值
- 赋值可以进行自动类型推断
- 在一个赋值语句中可以对多个变量进行同时赋值
赋值操作
- [var][变量名][类型][=][值],
var name int = 1 - [变量名][:][=][值],
a := 1 - 多变量赋值,
var ( a int = 1 b int = 2 ) - 交换操作,
a, b = b, a
常量定义
快速设置连续值
package try_test
import "testing"
// 设置连续值
const (
Monday = iota + 1 //1
Tuesday //2
Wednesday //3
Thursday //4
Friday //5
Saturday //6
sunday //7
)
// 设置位运算值
const (
Readable = 1 << iota //00000001
Writeable //00000010
Executable //0000100
)
func TestConstant(t *testing.T) {
t.Log(Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, sunday) //1 2 3 4 5 6 7
}
func TestConstant1(t *testing.T) {
t.Log(Readable, Writeable, Executable) // 1 2 4
}
基本数据类型
- 布尔型:bool
- 字符型:string
- 整型:int、int8、int16、int32、int64
- 无符号整型:uint、uint8、uint16、uint32、uint64、uintptr
- 字节型:byte(uint8的别名)
- Unicode编码值:rune(int32)
- 浮点型:float32、float64
- 复数型:complex64、complex128
类型转换
- Go语言不允许隐式类型转换
- 别名和原有类型也不能进行隐式类型转换
类型的预定义值
- math.MaxInt64
- math.MaxFloat64
- math.MaxUint32
指针类型
- 不支持指针运算
- string是只类型,其默认的初始化值是空字符串,而不是nil
算术运算符
A = 10, B = 20
| 标题 | 描述 | 实例 |
|---|---|---|
| + | 相加 | A + B 输出结果为30 |
| - | 相减 | A - B 输出结果为-10 |
| * | 相乘 | A * B 输出结果为200 |
| / | 相除 | B / A 输出结果为2 |
| % | 求余 | B % A 输出结果为0 |
| ++ | 自增 | A++ 输出结果为11 |
| -- | 自减 | A-- 输出结果为9 |
注意:Go语言没有前置的++,--
比较运算符
用==比较数组
- 相同维数且含有相同个数元素的数组才可以比较
- 每个元素相同的才相等
位运算符
&^按位置零,如果右边为1,则为0,如果右边为0,则为左边的数,如
1 &^ 0 -- 1
1 &^ 1 -- 0
0 &^ 1 -- 0
0 &^ 0 -- 0
循环
if条件
基本结构
支持变量赋值,通常可以用来对方法执行的错误进行判断
func TestIfMultiSec(t *testing.T) {
if a := 1 == 1; a {
t.Log("a == 1")
} else {
t.Log("a == others")
}
}
func TestIfMultiSec(t *testing.T) {
if v, err := SomeFun(); err == nil {
t.Log("a == 1")
} else {
t.Log("error!")
}
}
switch条件
- 条件表达式不限制为常量或者整数
- 单个case中,可以出现多个结果选项,使用逗号分隔,命中一个即可
- 与C语言规则相反,Go语言不需要用break来明确退出一个case
- 可以不设定switch之后的条件表达式,整个switch结构与多个if...else..的逻辑作用等同
如下等同与if...else...
数组的声明
// 定义数组
func TestArray(t *testing.T) {
var arr0 [3]int //一维初始化
arr1 := [4]int{1, 2, 3, 4} //固定长度初始化
arr2 := [...]int{1, 2, 3, 4, 5, 6} // 非固定长度初始化
arr3 := [3][3]int{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}} //二维数组固定长度舒适化
t.Log(arr0, arr1, arr2, arr3) // [0 0 0] [1 2 3 4] [1 2 3 4 5 6] [[1 2 3] [4 5 6] [7 8 9]]
}
// 遍历数组
func TestArrayTravel(t *testing.T) {
arr := [...]int{1, 3, 4, 5}
for i := 0; i < len(arr); i++ {
t.Log(arr[i])
}
//for-each
for idx, e := range arr {
t.Log(idx, e)
}
//不输出index
for _, e := range arr {
t.Log(e)
}
}
数组截取
截取规则:array[开始索引(包含), 结束索引(不包含)]
// 数组截取
func TestArraySplit(t *testing.T) {
arr := [...]int{1, 2, 3, 4, 5}
t.Log(arr[1:2]) //[2]
t.Log(arr[1:3]) //[2 3]
t.Log(arr[1:len(arr)]) //[2 3 4 5]
t.Log(arr[1:]) // [2 3 4 5]
t.Log(arr[:3]) //[1 2 3]
t.Log(arr[0:3]) //[1 2 3]
}
切片
内部结构
声明方式
// 切片声明方式
func TestSliceInit(t *testing.T) {
var s0 []int
t.Log(len(s0), cap(s0)) //0 0
s0 = append(s0, 1) //填充一个元素
t.Log(len(s0), cap(s0)) //1 1
s1 := []int{1, 2, 3, 4}
t.Log(len(s1), cap(s1)) //4 4
s2 := make([]int, 3, 5)
t.Log(len(s2), cap(s2)) //3 5
}
扩容方式
func TestSliceGrowing(t *testing.T) {
s := []int{}
for i := 0; i < 10; i++ {
s = append(s, i) // 会在超过数组元素的时候,创建一个新的空间(空间大小 * 2),然后赋值
t.Log(len(s), cap(s))
}
}
运行结果如图所示
当存储的元素超过cap的时候,会扩容两倍,也就是cap = cap * 2
切片共享存储结构
func TestSliceShareMemory(t *testing.T) {
year := []string{"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}
Q2 := year[3:6]
//cap的大小等于len(year)减去Q2[0]之前的元素的数量
t.Log(Q2, len(Q2), cap(Q2)) //[Apr May Jun] 3 9
summer := year[5:8]
t.Log(summer, len(summer), cap(summer)) //[Jun Jul Aug] 3 7
summer[0] = "unknow" //影响整个共享空间
t.Log(Q2) //[Apr May unknow]
t.Log(year) // [Jan Feb Mar Apr May unknow Jul Aug Sep Oct Nov Dec]
}
数组和切片的区别
- 容量是否可伸缩:数组容量固定,切片容量可以伸缩
- 是否可以比较:数组内容可以比较,切片不行
本文章参考来自Go语言从入门到实战