Go语言基础1

Go语言程序
语法要求:严格区分大小写;一行一行编译,一行只写一条语句;go语言定义的变量或者import的包如果没有使用,代码不能编译通过
转义字符的使用:回车\r 从当前行的最前面开始输出,覆盖掉以前的内容

#编译并生成可执行文件 go build 文件名.go

#编译生成可执行程序并运行 go run 源码文件.go

go env 查看环境信息
go text
  • go语言自带测试工具,会自动读取源码目录下面名为*_test.go的文件,生成并运行测试用的可执行文件
常用命令行
关键字
go语言关键字以及使用方式
数据类型
1命名规则
  • 数字不能开头
  • 区分大小写
  • 允许使用字母数字下划线
  • 不允许使用关键字
  • 见名知意
2基本数据类型
  • 派生数据类型
    • 指针,数组,结构体,通道,切片,函数,接口,map
  • 基本数据类型
    • 布尔,数值,字符串
驼峰式命名:
小驼峰如myName可以在包内部使用,大驼峰如MyName可以被外部函数使用
ASCII码:0-31控制字符 使用转义字符表示内容,32-126 默认字符
127 del 字符
一个中文汉字占三个字符
3类型转换
package main ? import "fmt" ? func main() { //去市场买菜 price := 3.25 weight := 5 //fmt.Printf("%T\n", price) //fmt.Printf("%T\n", weight) //sum := price * float64(weight) ? //浮点型转整型,会丢失精度 sum := int(price * float64(weight)) fmt.Println(sum) }

func main() { // type tune = int32两个数据类型可以计算 ch := 'A'//rune == int32 var b int32 = 100 fmt.Println(ch+b) }

4派生数据类型
数组
一组具有相同数据类型在内存中有序储存的数据集合
数组的长度在定义后不可以修改
func main() { // type tune = int32两个数据类型可以计算 //ch := 'A'//rune == int32 //var b int32 = 100 //fmt.Println(ch+b) //var arr []int 默认值为0 //使用数组名+下标进行数组初始化下标是从0开始的到数组最大元素个数-1 //var arr [10]int //arr[0] = 123 arr := [10]int{1,2,3,4,5,6,7,8,9,10} //fmt.Println(len(arr)) //遍历数组元素 //for i := 0; i < len(arr); i++{ //fmt.Println(arr[i]) //} for i, j := range arr{ fmt.Println(i, j) } }

运行结果如下
  • 如果不赋值的话,默认值为0

数组内存存储
func main() { arr := [10]int{1,2,3,4,5,6,7,8,9,10} for i := 0; i < len(arr); i++{ //&取地址运算符 fmt.Println(&arr[i]) } }

切片
一组具有相同数据类型在内存中有序储存的可扩容的数据集合
func main4() { //切片的定义和使用 //var 切片名 []数据类型 //var slice []int //var slice []int = make([]int, 10) //slice[0]=123 var slice []int fmt.Println(len(slice)) //计算长度 fmt.Println(cap(slice)) //计算容量 //使用append对切片进行扩容 slice = append(slice, 1,2,3,4,5) fmt.Println(len(slice)) fmt.Println(cap(slice)) fmt.Println(slice) }

切片的截取
//func main5() { ////切片的截取 //slice := []int{1,2,3,4,5,6,7,8,9,10} ////左闭右开包含起始下标 不包含结束下标 ////s := slice[2:7] ////s := slice[:5] //s := slice[2:5:6] //实际容量=容量-起始下标 //s[0] = 333 ////切片的截取是将新的切片指向原切片的内存地址修改一个会影响另一个 //fmt.Println(s) //fmt.Println(slice) //}

切片的拷贝
func main() { slice := []int{1,2,3,4,5} //s := slice //s[2] = 33 //在储存两个内容完全相同改变一个值不会相互影响 s := make([]int, 5) copy(s, slice) s[2] = 33 fmt.Println(s) fmt.Println(slice) }

map
//func main7() { ////map的定义 ////var 字典名 map[键类型]值类型 ////var m map[int]string = make(map[int]string, 10) ////m[1001] = "键盘" ////m[8888] = "鼠标" ////map是无序的集合 //m := map[int]string{1:"dfg", 2:"freg"} //for k, v := range m{ //fmt.Println(k, v) //} //} func main() { m := make(map[int]string) m[1] = "sdgf" m[2] = "trhh" if v, ok := m[1]; ok{ fmt.Println(v) }else{ fmt.Println("不存在") } delete(m, 1) fmt.Println(len(m)) fmt.Println(m) }

new和make的区别:
  • 两者都是用来做内存分配的
  • make只用于slice,map 以及channel的初始化,返回的还是这三个引用类本身
  • 而new
  • 用于类型的内存分配,并且内存对应的值为类型零值,返回的是指向类型的指针
指针
go语言中函数传参都是值拷贝,记住两个符号:&(取地址)和*(根据地址取值)
//func main9() { //a := 10 ////取出变量a所在内存的地址 //var p *int = &a //fmt.Println(p) //fmt.Println(&a) ////通过指针间接修改变量的值 //*p = 123 //fmt.Println(p) //} func main() { //error //定义指针 默认值为nil 指向内存地址编号为0的空间 内存地址0-255为系统占用 不允许用户读写操作 //var p *int //*p = 123 //fmt.Println(*p) //开辟数据类型大小的空间返回值为指针类型 //new(数据类型) var p *int p = new(int) *p = 123 fmt.Println(*p) ? }

流程控制
if语句
//if 表达式{} 如果表达式为真 执行{}的代码 ////if 表达式{代码1} else{代码2} 如果表达式为真,执行代码1 // ////score := 0 ////fmt.Scan(&score)//阻塞式请求 ////if score > 700{ ////fmt.Println("我问问") ////}else if score > 600{ ////fmt.Println("而政府") ////}else{ ////fmt.Println("梵蒂冈") ////}

switch语句
////day := 0 ////var m int ////fmt.Scan(&m) ////switch m { ////case 1, 3, 5, 7, 8, 10, 12: ////day = 31 //////fallthrough //执行完当前分支 继续向下执行 ////case 2: ////day = 29 ////} ////fmt.Println(day) ////浮点型因为精度问题可能在switch中认为是同一个值 ////pi := 3.14 ////switch pi{ ////case 3.14: ////fmt.Println(pi) ////case 3: ////fmt.Println(pi) ////} ////score := 0 ////fmt.Scan(&score) ////switch { ////case score > 700: ////fmt.Println("df") ////case score > 600: ////fmt.Println("fs") ////default: ////fmt.Println("cds") ////} ?

for语句
func main() { /* for 表达式1:表达式2:表达式3{ 代码体 } for 表达式{ 代码体 } for range 集合{ 代码体 } */ //sum := 0 //for i := 1; i <= 100; i++{ //sum += i //} //fmt.Println(sum) //嵌套循环 //for i := 1; i<=5; i++{ //for j := 1; j<=5; j++{ //fmt.Println(i,j) //} //} //冒泡排序 slice := []int{6, 4, 8, 3, 5} for i := 0; i

跳出语句
break语句:在循环语句中使用break跳出语句
continue语句:在循环语句中,如果希望立即终止本次循环,并执行下一次循环,就需要用到continue
函数
函数定义
func 函数名(参数)(返回值){ 函数体 }

//func sayHello(){ ////定义不需要string类型的name参数 //fmt.Println("hello") //} //func sayHello2(name string){ //fmt.Println("hello", name) //} //go语言中没有默认参数 //可变参数与不可变参数放在一起时,可变参数放在最后 func intSum(a int, b int) int { sum := a+b return sum } //也可以定义多返回值 func calc(a, int b) (sum, sub int){ sum = a + b sub = a - b return } func main() { x, y := calc(100, 200) fmt.Println(x, y) //fmt.Println(intSum(2,3)) }

defer语句
先被defer的语句最后执行,最后被defer的语句最先被执行
func main() { //defer:延迟执行 fmt.Println("start...") defer fmt.Println(1) defer fmt.Println(2) defer fmt.Println(3) fmt.Println("end") //fmt.Println(intSum(2,3)) }

函数进阶
var num = 10 func testGlobal(){ num := 100 name := "wowowo" //可以在函数中使用变量 //先在自己函数中查找,找到了就用自己函数中的 //函数中找不到变量就往外层找 fmt.Println("数字是:", num) fmt.Println(name) } func main() { testGlobal() }

  • 闭包和匿名函数
    //匿名函数和闭包 //定义一个函数它的返回值是一个函数 //把函数作为返回值 func a(name string) func(){ //name := "fdsf" return func() { fmt.Println("hello", name) } } func main() { //闭包=函数+外层变量的引用 r := a("jncxu") //r是一个闭包 r()//相当于执行了a函数内部的匿名函数 }


  • panic和recover
    go语言中没有异常机制,但是使用panic和recover模式处理机制错误。panic可以在任何地方引发,但recover只有在defer调用的函数中有效
    func a(){ fmt.Println("func") } func b(){ defer func() { err := recover() if err != nil{ fmt.Println("func b error") } }() panic("panic in b") } func main() { a() b() }

    运行结果
    GOROOT=G:\golang_env #gosetup GOPATH=D:\work\goCode #gosetup G:\golang_env\bin\go.exe build -o C:\Users\PC\AppData\Local\Temp\___go_build_two_go.exe D:\work\goCode\src\studyGo\two.go #gosetup C:\Users\PC\AppData\Local\Temp\___go_build_two_go.exe #gosetup func func b error ? Process finished with exit code 0

结构体
类型别名和自定义类型
  • 自定义类型 可以使用type关键字来自定义类型
    type MyInt int

  • 类型别名 规定:TypeAlias只是Type的别名,就像一个人有小名,大名,英文名但所有名字都是一个人
    type TypeAlias = Type

  • 类型定义和类型别名的区别
    type MyInt int type MiInt = int func main() { var i MyInt var j MiInt fmt.Printf("type of i:%T\n", i) fmt.Printf("type of j:%T\n", j) ? }

    输出
    GOROOT=G:\golang_env #gosetup GOPATH=D:\work\goCode #gosetup G:\golang_env\bin\go.exe build -o C:\Users\PC\AppData\Local\Temp\___go_build_two_go.exe D:\work\goCode\src\studyGo\two.go #gosetup C:\Users\PC\AppData\Local\Temp\___go_build_two_go.exe #gosetup type of i:main.MyInt type of j:int ? Process finished with exit code 0

结构体定义与实例化
  • 定义 go语言提供了一种自定义数据类型,可以封装多个基本数据类型,这 种数据类型叫做结构体(struct) t 通过struct来实现面向对象
  • 使用type和struct关键字来定义结构体
    //定义结构体 type person struct { name, city string ageint8 }

  • 实例化
    type person struct { name, city string ageint8 } ? func main() { var p person p.name = "fncsdjf" p.age = 19 p.city = "fds" fmt.Printf("p=%#v\n", p) fmt.Println(p.name) }

  • 匿名结构体
    func main() { var user struct{ name string married bool } user.name = "fdsf" user.married = false }

结构体的初始化
  • 键值对初始化
  • 值的列表进行初始化
    func main() { //键值对初始化 //a := &person{ //name: "你你你", //city: "背景", //age: 19, //} //fmt.Printf("%#v\n", a) //值的列表进行初始化 b := &person{ "我问问", "背景", 19, } fmt.Printf("%#v\n", b) }

  • 注意
    • 必须初始化结构体的所有字段
    • 初始值的填充顺序必须与字段在结构体中的声明顺序一致
    • 该方式不能和键值初始化方式混用
【Go语言基础1】构造函数
type person struct { name, citystring ageint8 } //构造函数 func newPerson(name, city string, age int8) *person{ return &person{ name: name, city: city, age:age, } } func main() { c := newPerson("gfbb", "vcv", int8(19)) fmt.Printf("type:%T value:%#v\n", c, c) }

    推荐阅读