共计 10003 个字符,预计需要花费 26 分钟才能阅读完成。
hello GO
这里应用 vscode
- 装置插件 go
-
新建 hello 文件夹, 创立 main.go 文件
package main import "fmt" func main(){fmt.Println("Hello") }
- 关上命令行
- 关上命令行
- 执行 go build 这时同目录会创立一个 hello.exe 的文件(我这里应用的是 win 电脑)
也能够应用 go build -o aaa.exe 指定文件名
也间接输入可应用 go run main.go
跨平台编译
只须要指定指标操作系统的平台和处理器架构即可:
SET CGO_ENABLED=0 // 禁用 CGO
SET GOOS=linux // 指标平台是 linux
SET GOARCH=amd64 // 指标处理器架构是 amd64
而后再执行 go build
命令,失去的就是可能在 Linux 平台运行的可执行文件了。
Mac 下编译 Linux 和 Windows 平台 64 位 可执行程序:
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build
Linux 下编译 Mac 和 Windows 平台 64 位可执行程序:
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build
Windows 下编译 Mac 平台 64 位可执行程序:
SET CGO_ENABLED=0
SET GOOS=darwin
SET GOARCH=amd64
go build
根底
// 单行正文
/*
多行正文
*/
fmt.Println(‘ 打印输出 ’)
一行代码不需加分号
变量申明后必须应用, 不应用会报错
缩进没有严格要求
变量和常量
标书与关键字
Go 语言中标识符由字母数字和 _
(下划线)组成,并且只能以字母和_
结尾。
关键词
25 个关键词
break default func interface select
case defer go map struct
chan else goto package switch
const fallthrough if range type
continue for import return var
37 个保留词
Constants: true false iota nil
Types: int int8 int16 int32 int64
uint uint8 uint16 uint32 uint64 uintptr
float32 float64 complex128 complex64
bool byte rune string error
Functions: make len cap new append copy close delete
complex real imag
panic recover
变量
申明: var 变量名 变量类型
单个申明
var aaa string
var age int
var iss bool
批量申明
var (
a string
b int
c bool
)
变量初始化: var 变量名 类型 = 表达式
var name string = "aa"
一次初始化多个变量
var name,age = "bb",20
短变量申明(申明并初始化) :=
n:=10
m:=50
匿名变量: 用一个下划线 _
示意
匿名变量不占用命名空间,不会分配内存,所以匿名变量之间不存在反复申明。(在 Lua
等编程语言里,匿名变量也被叫做哑元变量。)
func foo() (int, string) {return 10, "Q1mi"}
func main() {x, _ := foo()
_, y := foo()
fmt.Println("x=", x)
fmt.Println("y=", y)
}
留神:
函数外的每个语句都必须以关键字开始(var、const、func 等)
:=
不能应用在函数外。
_
多用于占位,示意疏忽值。
常量 const
const a = 'dsadasd'
和变量相似
const (
a string
b int
c bool
)
iota : go 语言的常量计数器
iota
在 const 关键字呈现时将被重置为 0
const (
n1 = iota //0
n2 //1
n3 //2
n4 //3
)
应用_调过某些值
const (
n1 = iota //0
n2 //1
_
n4 //3
)
iota
申明两头插队
const (
n1 = iota //0
n2 = 100 //100
n3 = iota //2
n4 //3
)
const n5 = iota //0
多个 iota
定义在一行
const (
a, b = iota + 1, iota + 2 //1,2
c, d //2,3
e, f //3,4
)
数据类型
整型
Go 语言中有丰盛的数据类型,除了根本的整型、浮点型、布尔型、字符串外,还有数组、切片、构造体、函数、map、通道(channel)等。
类型 | 形容 |
---|---|
uint8 | 无符号 8 位整型 (0 到 255) |
uint16 | 无符号 16 位整型 (0 到 65535) |
uint32 | 无符号 32 位整型 (0 到 4294967295) |
uint64 | 无符号 64 位整型 (0 到 18446744073709551615) |
int8 | 有符号 8 位整型 (-128 到 127) |
int16 | 有符号 16 位整型 (-32768 到 32767) |
int32 | 有符号 32 位整型 (-2147483648 到 2147483647) |
int64 | 有符号 64 位整型 (-9223372036854775808 到 9223372036854775807) |
非凡整型
类型 | 形容 |
---|---|
uint | 32 位操作系统上就是uint32 ,64 位操作系统上就是uint64 |
int | 32 位操作系统上就是int32 ,64 位操作系统上就是int64 |
uintptr | 无符号整型,用于寄存一个指针 |
进制
// 十进制
var a int = 10
fmt.Printf("%d \n", a) // 10
fmt.Printf("%b \n", a) // 1010 占位符 %b 示意二进制
// 八进制 以 0 结尾
var b int = 077
fmt.Printf("%o \n", b) // 77
// 十六进制 以 0x 结尾
var c int = 0xff
fmt.Printf("%x \n", c) // ff
fmt.Printf("%X \n", c) // FF
浮点型
Go 语言反对两种浮点型数:float32
和float64
package main
import (
"fmt"
"math"
)
func main() {fmt.Printf("%f\n", math.Pi)
fmt.Printf("%.2f\n", math.Pi)
}
复数
complex64 和 complex128
复数有实部和虚部,complex64 的实部和虚部为 32 位,complex128 的实部和虚部为 64 位。
var c1 complex64
c1 = 1 + 2i
var c2 complex128
c2 = 2 + 3i
fmt.Println(c1)
fmt.Println(c2)
布尔值
Go 语言中以 bool
类型进行申明布尔型数据,布尔型数据只有 true(真)
和false(假)
两个值。
留神:
- 布尔类型变量的默认值为
false
。 - Go 语言中不容许将整型强制转换为布尔型.
- 布尔型无奈参加数值运算,也无奈与其余类型进行转换。
字符串
s1 := "hello"
s2 := "你好"
字符串本义符
本义符 | 含意 |
---|---|
\r |
回车符(返回行首) |
\n |
换行符(间接跳到下一行的同列地位) |
\t |
制表符 |
\' |
单引号 |
\" |
双引号 |
\\ |
反斜杠 |
多行字符串 应用反引号
字符串的罕用操作
办法 | 介绍 |
---|---|
len(str) | 求长度 |
+ 或 fmt.Sprintf | 拼接字符串 |
strings.Split | 宰割 |
strings.contains | 判断是否蕴含 |
strings.HasPrefix,strings.HasSuffix | 前缀 / 后缀判断 |
strings.Index(),strings.LastIndex() | 子串呈现的地位 |
strings.Join(a[]string, sep string) | join 操作 |
byte 和 rune 类型
字符用单引号(’)包裹起来
nt8
类型,或者叫 byte 型,代表了ASCII 码
的一个字符。rune
类型,代表一个UTF- 8 字符
。
当须要解决中文、日文或者其余复合字符时,则须要用到 rune
类型。rune
类型理论是一个int32
批改字符串
要批改字符串,须要先将其转换成 []rune
或[]byte
,实现后再转换为string
。无论哪种转换,都会从新分配内存,并复制字节数组。
func changeString() {
s1 := "big"
// 强制类型转换
byteS1 := []byte(s1)
byteS1[0] = 'p'
fmt.Println(string(byteS1))
s2 := "白萝卜"
runeS2 := []rune(s2)
runeS2[0] = '红'
fmt.Println(string(runeS2))
}
类型转换
强制转换
T(表达式)
T 示意要转换的类型。表达式包含变量、简单算子和函数返回值等.
运算符
- 算术运算符
+ - * / %
- 关系运算符
== != > >= < <=
- 逻辑运算符
&& || !
-
位运算符
运算符 形容 & 参加运算的两数各对应的二进位相与。(两位均为 1 才为 1) \ 参加运算的两数各对应的二进位相或。(两位有一个为 1 就为 1) ^ 参加运算的两数各对应的二进位相异或,当两对应的二进位相异时,后果为 1。(两位不一样则为 1) << 左移 n 位就是乘以 2 的 n 次方。“a<<b”是把 a 的各二进位全副左移 b 位,高位抛弃,低位补 0。 >> 右移 n 位就是除以 2 的 n 次方。“a>>b”是把 a 的各二进位全副右移 b 位。 - 赋值运算符
= += -= *= /= %= <<= >>= &= |= ^=
流程管制
ifelse
if 表达式 1 {分支 1} else if 表达式 2 {分支 2} else{分支 3}
for
for 初始语句; 条件表达式; 完结语句{循环体语句}
残缺
func forDemo() {
for i := 0; i < 10; i++ {fmt.Println(i)
}
}
初始语句省略
func forDemo2() {
i := 0
for ; i < 10; i++ {fmt.Println(i)
}
}
初始语句 / 完结语句完结
func forDemo3() {
i := 0
for i < 10 {fmt.Println(i)
i++
}
}
有限循环
for {循环体语句}
for range(键值循环)
switch case
func switchDemo1() {
finger := 3
switch finger {
case 1:
fmt.Println("大拇指")
case 2:
fmt.Println("食指")
case 3:
fmt.Println("中指")
case 4:
fmt.Println("无名指")
case 5:
fmt.Println("小拇指")
default:
fmt.Println("有效的输出!")
}
}
func testSwitch3() {
switch n := 7; n {
case 1, 3, 5, 7, 9:
fmt.Println("奇数")
case 2, 4, 6, 8:
fmt.Println("偶数")
default:
fmt.Println(n)
}
}
fallthrough
语法能够执行满足条件的 case 的下一个 case,是为了兼容 C 语言中的 case 设计的。
func switchDemo5() {
s := "a"
switch {
case s == "a":
fmt.Println("a")
fallthrough
case s == "b":
fmt.Println("b")
case s == "c":
fmt.Println("c")
default:
fmt.Println("...")
}
}
输入:
a
b
goto
通过标签进行代码间的无条件跳转
func gotoDemo2() {
for i := 0; i < 10; i++ {
for j := 0; j < 10; j++ {
if j == 2 {
// 设置退出标签
goto breakTag
}
fmt.Printf("%v-%v\n", i, j)
}
}
return
// 标签
breakTag:
fmt.Println("完结 for 循环")
}
break(跳出循环)
break
语句能够完结 for
、switch
和select
的代码块。
func breakDemo1() {
BREAKDEMO1:
for i := 0; i < 10; i++ {
for j := 0; j < 10; j++ {
if j == 2 {break BREAKDEMO1}
fmt.Printf("%v-%v\n", i, j)
}
}
fmt.Println("...")
}
continue(持续下次循环)
func continueDemo() {
forloop1:
for i := 0; i < 5; i++ {
// forloop2:
for j := 0; j < 5; j++ {
if i == 2 && j == 2 {continue forloop1}
fmt.Printf("%v-%v\n", i, j)
}
}
}
数组
数组定义
var 数组变量名 [元素数量]T
一旦定义,长度不能变
初始化
func main() {var testArray [3]int // 数组会初始化为 int 类型的零值
var numArray = [3]int{1, 2} // 应用指定的初始值实现初始化
var cityArray = [3]string{"北京", "上海", "深圳"} // 应用指定的初始值实现初始化
fmt.Println(testArray) //[0 0 0]
fmt.Println(numArray) //[1 2 0]
fmt.Println(cityArray) //[北京 上海 深圳]
}
func main() {var testArray [3]int
var numArray = [...]int{1, 2}
var cityArray = [...]string{"北京", "上海", "深圳"}
fmt.Println(testArray) //[0 0 0]
fmt.Println(numArray) //[1 2]
fmt.Printf("type of numArray:%T\n", numArray) //type of numArray:[2]int
fmt.Println(cityArray) //[北京 上海 深圳]
fmt.Printf("type of cityArray:%T\n", cityArray) //type of cityArray:[3]string
}
func main() {a := [...]int{1: 1, 3: 5}
fmt.Println(a) // [0 1 0 5]
fmt.Printf("type of a:%T\n", a) //type of a:[4]int
}
数组遍历
func main() {var a = [...]string{"北京", "上海", "深圳"}
// 办法 1:for 循环遍历
for i := 0; i < len(a); i++ {fmt.Println(a[i])
}
// 办法 2:for range 遍历
for index, value := range a {fmt.Println(index, value)
}
}
多维数组
func main() {a := [3][2]string{{"北京", "上海"},
{"广州", "深圳"},
{"成都", "重庆"},
}
for _, v1 := range a {
for _, v2 := range v1 {fmt.Printf("%s\t", v2)
}
fmt.Println()}
}
北京 上海
广州 深圳
成都 重庆
多维数组 只有第一层 能够应用 ...
来让编译器推导数组长度。例如:
// 反对的写法
a := [...][2]string{{"北京", "上海"},
{"广州", "深圳"},
{"成都", "重庆"},
}
// 不反对多维数组的内层应用...
b := [3][...]string{{"北京", "上海"},
{"广州", "深圳"},
{"成都", "重庆"},
}
数组是值类型
数组是值类型,赋值和传参会复制整个数组。因而扭转正本的值,不会扭转自身的值。
func modifyArray(x [3]int) {x[0] = 100
}
func modifyArray2(x [3][2]int) {x[2][0] = 100
}
func main() {a := [3]int{10, 20, 30}
modifyArray(a) // 在 modify 中批改的是 a 的正本 x
fmt.Println(a) //[10 20 30]
b := [3][2]int{{1, 1},
{1, 1},
{1, 1},
}
modifyArray2(b) // 在 modify 中批改的是 b 的正本 x
fmt.Println(b) //[[1 1] [1 1] [1 1]]
}
留神:
- 数组反对“==“、”!=”操作符,因为内存总是被初始化过的。
[n]*T
示意指针数组,*[n]T
示意数组指针。
切片
一个领有雷同类型元素的可变长度的序列
定义
var name []T
长度 / 容量
通过应用内置的 len()
函数求长度,应用内置的 cap()
函数求切片的容量
len(s), cap(s)
应用 make()函数创立结构切片
make([]T, size, cap)
T: 切片的元素类型
size: 切片中元素的数量
cap: 切片的容量
a := make([]int, 2, 10)
fmt.Println(a) //[0 0]
fmt.Println(len(a)) //2
fmt.Println(cap(a)) //10
判断切片是否为空
请始终应用 len(s) == 0
来判断,而不应该应用 s == nil
来判断。
切片不能间接比拟
切片赋值拷贝
s1 := make([]int, 3) //[0 0 0]
s2 := s1 // 将 s1 间接赋值给 s2,s1 和 s2 共用一个底层数组
切片遍历
遍历形式和数组是统一的
append
func main(){var s []int
s = append(s, 1) // [1]
s = append(s, 2, 3, 4) // [1 2 3 4]
s2 := []int{5, 6, 7}
s = append(s, s2...) // [1 2 3 4 5 6 7]
}
var 申明的零值切片能够在 append()
函数间接应用,无需初始化。
s := []int{} // 没有必要初始化
s = append(s, 1, 2, 3)
var s = make([]int) // 没有必要初始化
s = append(s, 1, 2, 3)
追加切片
var citySlice []string
// 追加一个元素
citySlice = append(citySlice, "北京")
// 追加多个元素
citySlice = append(citySlice, "上海", "广州", "深圳")
// 追加切片
a := []string{"成都", "重庆"}
citySlice = append(citySlice, a...)
fmt.Println(citySlice) //[北京 上海 广州 深圳 成都 重庆]
copy
copy(destSlice, srcSlice []T)
srcSlice: 数据起源切片
destSlice: 指标切片
func main() {// copy()复制切片
a := []int{1, 2, 3, 4, 5}
c := make([]int, 5, 5)
copy(c, a) // 应用 copy()函数将切片 a 中的元素复制到切片 c
fmt.Println(a) //[1 2 3 4 5]
fmt.Println(c) //[1 2 3 4 5]
c[0] = 1000
fmt.Println(a) //[1 2 3 4 5]
fmt.Println(c) //[1000 2 3 4 5]
}
删除元素
没有删除切片元素的专用办法,咱们能够应用切片自身的个性来删除元素
从切片 a 中删除索引为 index
的元素,操作方法是a = append(a[:index], a[index+1:]...)
func main() {
// 从切片中删除元素
a := []int{30, 31, 32, 33, 34, 35, 36, 37}
// 要删除索引为 2 的元素
a = append(a[:2], a[3:]...)
fmt.Println(a) //[30 31 33 34 35 36 37]
}
map
map 定义
map[KeyType]ValueType
KeyType: 示意键的类型。ValueType: 示意键对应的值的类型。
map 类型的变量默认初始值为 nil,须要应用 make()函数来分配内存。语法为:
make(map[KeyType]ValueType, [cap])
根本应用
func main() {scoreMap := make(map[string]int, 8)
scoreMap["张三"] = 90
scoreMap["小明"] = 100
fmt.Println(scoreMap)
fmt.Println(scoreMap["小明"])
fmt.Printf("type of a:%T\n", scoreMap)
}
map[小明:100 张三:90]
100
type of a:map[string]int
map 也反对在申明的时候填充元素
func main() {userInfo := map[string]string{
"username": "沙河小王子",
"password": "123456",
}
fmt.Println(userInfo) //
}
判断某个键是否存在
value, ok := map[key]
func main() {scoreMap := make(map[string]int)
scoreMap["张三"] = 90
scoreMap["小明"] = 100
// 如果 key 存在 ok 为 true,v 为对应的值;不存在 ok 为 false,v 为值类型的零值
v, ok := scoreMap["张三"]
if ok {fmt.Println(v)
} else {fmt.Println("查无此人")
}
}
map 遍历
func main() {scoreMap := make(map[string]int)
scoreMap["张三"] = 90
scoreMap["小明"] = 100
scoreMap["娜扎"] = 60
for k, v := range scoreMap {fmt.Println(k, v)
}
}
遍历 map 时的元素程序与增加键值对的程序无关。
delete
delete(map, key)
func main(){scoreMap := make(map[string]int)
scoreMap["张三"] = 90
scoreMap["小明"] = 100
scoreMap["娜扎"] = 60
delete(scoreMap, "小明")// 将小明:100 从 map 中删除
for k,v := range scoreMap{fmt.Println(k, v)
}
}
依照指定程序遍历 map
func main() {rand.Seed(time.Now().UnixNano()) // 初始化随机数种子
var scoreMap = make(map[string]int, 200)
for i := 0; i < 100; i++ {key := fmt.Sprintf("stu%02d", i) // 生成 stu 结尾的字符串
value := rand.Intn(100) // 生成 0~99 的随机整数
scoreMap[key] = value
}
// 取出 map 中的所有 key 存入切片 keys
var keys = make([]string, 0, 200)
for key := range scoreMap {keys = append(keys, key)
}
// 对切片进行排序
sort.Strings(keys)
// 依照排序后的 key 遍历 map
for _, key := range keys {fmt.Println(key, scoreMap[key])
}
}
元素为 map 类型的切片
func main() {var mapSlice = make([]map[string]string, 3)
for index, value := range mapSlice {fmt.Printf("index:%d value:%v\n", index, value)
}
fmt.Println("after init")
// 对切片中的 map 元素进行初始化
mapSlice[0] = make(map[string]string, 10)
mapSlice[0]["name"] = "小王子"
mapSlice[0]["password"] = "123456"
mapSlice[0]["address"] = "沙河"
for index, value := range mapSlice {fmt.Printf("index:%d value:%v\n", index, value)
}
}
值为切片类型的 map
func main() {var sliceMap = make(map[string][]string, 3)
fmt.Println(sliceMap)
fmt.Println("after init")
key := "中国"
value, ok := sliceMap[key]
if !ok {value = make([]string, 0, 2)
}
value = append(value, "北京", "上海")
sliceMap[key] = value
fmt.Println(sliceMap)
高颜值后盾管理系统收费应用 ### 子枫后盾管理系统 ###,可在宝塔面板间接装置
欢送关注我的公众号:子枫的微妙世界,取得独家整顿的学习资源和日常干货推送。
如果您对我的其余专题内容感兴趣,中转我的集体博客:www.wangmingchang.com。