go学习笔记1

hello GO

这里使用vscode

  1. 安装插件go

  2. 新建hello文件夹,创建main.go文件

    package main
    import "fmt"
    func main(){
     fmt.Println("Hello")
    }
    
    1. 打开命令行

      image-20200827134240655
  3. 执行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语言支持两种浮点型数:float32float64

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(假)两个值。

注意:

  1. 布尔类型变量的默认值为false
  2. Go 语言中不允许将整型强制转换为布尔型.
  3. 布尔型无法参与数值运算,也无法与其他类型进行转换。

字符串

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类型

字符用单引号(’)包裹起来

  1. nt8类型,或者叫 byte 型,代表了ASCII码的一个字符。
  2. 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. 算术运算符 + - * / %

  2. 关系运算符 == != > >= < <=

  3. 逻辑运算符&& || !

  4. 位运算符

    运算符 描述
    & 参与运算的两数各对应的二进位相与。 (两位均为1才为1)
    | 参与运算的两数各对应的二进位相或。 (两位有一个为1就为1)
    ^ 参与运算的两数各对应的二进位相异或,当两对应的二进位相异时,结果为1。 (两位不一样则为1)
    << 左移n位就是乘以2的n次方。 “a<<b”是把a的各二进位全部左移b位,高位丢弃,低位补0。
    >> 右移n位就是除以2的n次方。 “a>>b”是把a的各二进位全部右移b位。
  5. 赋值运算符= += -= *= /= %= <<= >>= &= |= ^=

流程控制

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语句可以结束forswitchselect的代码块。

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]]
}

注意:

  1. 数组支持 “==“、”!=” 操作符,因为内存总是被初始化过的。
  2. [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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270