Go基础--笔记
Posted 荒唐了年少
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Go基础--笔记相关的知识,希望对你有一定的参考价值。
Go语言基础部分学习笔记:
(系统不支持插入Go代码 下面插入的代码选用的格式是C++......)
以下内容更多的并非解释相关知识是什么意思,而是给有过其他语言基础的人看看Go语言的语法格式,如何快速使用Go
代码可以去Github下载:wangmlshadow/notebook-Go: Go语言学习 (github.com)
首先是学任何一个语言都会首先去做的事,HelloWorld:
package main import "fmt" // 行注释 /* 块注释 */ // 快速注释 ctrl + / func main() { // print fmt.Println("Hello World") }
变量部分:
和大部分语言一样,Go支持整形、浮点型、布尔类型、字符串类型,不过需要注意的是Go定义变量的方式
// 定义 // 格式:var 变量名 变量类型 var a int = 10 var b int b = a// 赋值 // 自动推导变量类型 PI := 3.1415
// 声明多个变量并赋值
c, d := 1, 2
字符和字符串:
package main import "fmt" func main() { var a byte = \'a\' var b string = "a" fmt.Println(a, b) str := "123456789" // len() 系统函数 计算字符串长度 length := len(str) fmt.Println(length) str1 := "哈哈哈哈" fmt.Println(len(str1))// 在Go中一个汉字等于3个字符 为了和Linux进行统一处理 }
常量的使用:
// 常量存储在数据区 变量存储在栈中 const a int = 10 fmt.Println(a)
怎么用输入输出:
可以看一下包fmt的文档,这里仅仅放一个例子
// 格式输入 var a int // & 取地址 fmt.Scan(&a) // %p 占位符 表示输出一个数据对应的内存地址 fmt.Printf("%p", &a)
运算符:
和大部分语言一样,包括算术运算符、关系运算符、逻辑运算符
// + - * / % // ++ -- 自增 自减只有放在变量后面的形式 没有放在前面的 a := 10 a++ fmt.Println(a) a-- fmt.Println(a) b := 3 c := a / b//整型相除仍然是整型 fmt.Println(c) // 赋值运算符 // = += -= /= *= // 逻辑运算符 // ! && || // 关系运算符 // > < == != >= <=
流程控制:
包括if else、switch、循环只有for
func main() { // 选择 // 注意格式 可嵌套 age := 17 if age < 18 { fmt.Println("未成年") } else if age >= 18 && age < 35 {// 注意 此处要写在同一行 fmt.Println("青年") } else {// 注意 此处要写在同一行 fmt.Println("成年") } // switch // 通过值进行选择 // switch中不能用浮点型数据 浮点型数据是一个约等于的数据 var w int fmt.Scan(&w) switch w { case 1: fmt.Println("星期一") fallthrough// 让switch执行下一个分支的代码 如果不写执行到下一个分支就会自动停止 这个程序会在输入 1 的时候会输出 星期一 星期二 case 2: fmt.Println("星期二") case 3: fmt.Println("星期三") case 4: fmt.Println("星期四") case 5: fmt.Println("星期五") case 6: fmt.Println("星期六") case 7: fmt.Println("星期日") default: fmt.Println("error") } // 循环结构 // go语言中只有一种循环结构 for循环 var i int for i = 1; i < 10; i++ { fmt.Println(i) } for j := 1; j < 10; j++ { fmt.Println(j) } for j := 1; j < 10; j++ { if j == 1 { continue } fmt.Println(j) } for ; ; {// 死循环 break// 跳出 } for{// 死循环另一种写法 break// 跳出 } }
函数的定义与使用:
函数中变量的作用域、传参等就不做介绍
package main import "fmt" func test() { fmt.Println("asdasd") } func test2(a int, b int) { fmt.Println(a + b) } func test3(a int, b int) (sum int) { sum = a + b return } // type 可以定义函数类型 // type 可以为已存在的类型起别名 type FUNCTYPE func() type FUNCTEST func(int, int) type FUNCDEM func(int, int)int func main() { // 定义函数类型变量 var f FUNCTYPE f = test // 通过函数变量调用函数 f() var f1 FUNCTEST f1 = test2 f1(1, 2) var f2 FUNCDEM f2 = test3 _ = f2(1, 2) }
匿名函数:
package main import "fmt" func main() { a, b := 1, 2 // 匿名函数 // 定义并调用 //func (a int, b int) { // fmt.Println(a + b) //}(a, b) f := func (a int, b int) { fmt.Println(a + b) } f(a, b) f1 := func (a int, b int) int { return a + b }(a, b) fmt.Println(f1) }
切片(或者说数组)的使用:
注意不要以为和Python的切片是一个意思,Go中的切片截取可以看作Python中的数组切片
package main import "fmt" // 切片作为函数参数 func test(s []int) { s[0] = 88// 切片传递地址 源切片数据也会被改变 fmt.Println(s) } func main() { // 数组定义 var 数组名 [元素个数]数据类型 // 切片定义 var 切片名 []数据类型 //var s []int //fmt.Println(s) // 自动推导类型创建切片 s := make([]int, 5)// 设置长度为5 s[0] = 1 s[1] = 2 //s[6] = 7// error 越界 // 使用append添加元素 fmt.Println(len(s)) s = append(s, 6, 7 , 8, 9) fmt.Println(len(s)) fmt.Println(s) // 查看容量 fmt.Println(cap(s)) // go的切片不是python的切片 可以看作C++的vector // 推荐使用切片而不是数组 // 切片的截取 类似于python的切片 fmt.Println(s[2:]) fmt.Println(s[:4]) fmt.Println(s[2:4]) fmt.Println(s[0:2:4])// low = 0 height = 2 max = 4 cap = max - low slice := s[2:4]// 切片数据仍然指向原始的s 修改slice的话s也会被修改 slice[0] = 9 slice[1] = 9 fmt.Println(slice) fmt.Println(s) s2 := make([]int, len(s)) copy(s2, s)// 拷贝操作 深拷贝 s2需要有足够的空间存放拷贝过来的数据 s2[0] = 100 fmt.Println(s) fmt.Println(s2) // 也可因copy切片的截取部分 test(s) fmt.Println(s) }
map的使用:
package main import "fmt" // map作为函数参数 是地址传递 func test(m map[int]string) { m[1] = "AAAAAA" } func main() { // map key 必须是基本数据类型 //var m map[int]string m := make(map[int]string, 1)// map自动扩容 fmt.Println(m) m[1] = "asdasd" m[2] = "safasd" m[9] = "asfkasd" fmt.Println(m) fmt.Println(m[2]) for k, v := range m { fmt.Println(k, v) } // 判断是否存在key v1, ok1 := m[1] v5, ok5 := m[5] if ok1 { fmt.Println(v1) } else { fmt.Println("key 1 not existed") } if ok5 { fmt.Println(v5) } else { fmt.Println("key 5 not existed") } // 删除map中的元素 fmt.Println(m) delete(m, 1) // delete删除map元素时 表示的时若可key存在就删除 不存在也不会报错 delete(m, 5) fmt.Println(m) test(m) fmt.Println(m) }
结构体的定义和使用:
Go中的结构体可以看作C++的类,而不是C中仅有数据成员的结构体
package main import ( "fmt" ) func test(s student) { fmt.Println(s) } type student struct { id int age int sex string } func main() { var s student s.id = 101 s.age = 12 s.sex = "man" fmt.Println(s) var s2 student = student{102, 13, "male"} s3 := student{103, 14, "man"} fmt.Println(s2, s3) s4 := s fmt.Println(s4) // 结构体的比较 // != // == // 结构体切片 //var ss []student ss := make([]student, 10) ss = append(ss, student{104, 11, "man"}) fmt.Println(ss) m := make(map[int]student) m[1] = s m[2] = s2 fmt.Println(m) }
指针:
package main import "fmt" // 指针作为函数参数 func test(p *int) { *p = 99 fmt.Println(*p) } // 切片指针作为函数参数 func test2(p *[]int) { *p = append(*p, 999, 999) } type student struct { id int name string } func main() { var a int = 10 // 定义整形指针变量 指向a的地址 // 与C++类似 var pa *int = &a fmt.Println(pa) *pa = 20 fmt.Println(a) // 为指针变量创建一块内存空间 var p1 *int // 堆 p1 = new(int) fmt.Println(*p1) fmt.Println(p1) test(&a) test(p1) fmt.Println(a) fmt.Println(*p1) // 数组指针 var arr [5]int = [5]int{1, 2, 3, 4, 5} fmt.Println(arr) fmt.Printf("%p\\n", &arr) // 数组指针定义时给出的数组大小需要和赋值给他的数组大小一样 // var parr *[5]int // parr = &arr parr := &arr fmt.Println(*parr) fmt.Println(parr) fmt.Printf("%T\\n", parr) // 切片指针 var slice []int = []int{1, 2, 3, 4, 5} ppslice := &slice fmt.Println(slice) fmt.Println(*ppslice) fmt.Println(ppslice)// 二级指针 fmt.Printf("%T\\n", ppslice) fmt.Println(*ppslice) // 切片名本身就是一个地址 (*ppslice)[0] = 9 fmt.Println(slice) // ppslice[0] = 9 error 和数组指针不同 test2(ppslice) fmt.Println(slice) // 用new创建切片指针空间 var p3 *[]int fmt.Printf("%p\\n", p3) p3 = new([]int) fmt.Printf("%p\\n", p3) *p3 = append(*p3, 1, 2, 3, 4, 5) for i := 0; i < len(*p3); i++ { fmt.Println((*p3)[i]) } // 指针数组 指针切片 a, b, c := 1, 2, 3 var pointarr [3]*int = [3]*int{&a, &b, &c} *pointarr[0] = 99 fmt.Println(a) // 指针切片 var pointslice []*int pointslice = append(pointslice, &a, &b, &c) *pointslice[2] = 99 fmt.Println(c) // 结构体指针 var st student = student{101, "bob"} fmt.Println(st) var pstudent *student = &st pstudent.id = 102 pstudent.name = "marrys" fmt.Println(st) // 多级指针 x := 10 px := &x ppx := &px }
同名字段个匿名字段:
package main import "fmt" type person struct { name string age int sex string } // 结构体嵌套 type student struct { person// 匿名字段 id int score int name string// 同名字段 } type student2 struct { *person// 指针匿名字段 id int score int name string// 同名字段 } func main() { // var stu student = student{person{...}, ...} var stu student stu.id = 101 stu.score = 100 stu.name = "nana" stu.person.name = "lala" stu.person.age = 18 stu.sex = "female" fmt.Println(stu) var stu2 student2 //stu2.person.name = "kaka"// invalid memory address or nil pointer dereference stu2.person = new(person) stu2.name = "baba" stu2.person.name = "kaka" fmt.Println(stu2) }
多重继承:
package main import "fmt" type test1 struct { name string id int } type test2 struct { test1 sex string age int } type test3 struct { test2 score int } type test4 struct { test1 test2 score int } func main() { var s test3 s.name = "asda" s.age = 19 s.score = 1213 fmt.Println(s) }
结构体的方法的定义和使用:
可以看作类的成员函数
package main import "fmt" //func add(a, b int) int { // return a + b //} // 起别名 type Int int // 方法 // func (方法接收者)方法名(参数列表)返回值类型 func (a Int) add (b Int) Int { return a + b } type student struct { name string age int sex string } // 为结构体定义别名 func (stu student) PrintInfo () { fmt.Println(stu.sex) fmt.Println(stu.name) fmt.Println(stu.age) } func (stu *student) Rename () { stu.name = "asdasdasd" } // 方法的继承 type test struct { student index int } // 方法的重写 func (t test) PrintInfo () { t.student.PrintInfo() fmt.Println(t.index) } // 方法类型和方法的值 func main() { // 根据数据类型绑定方法 var a Int = 1 var b Int = 3 fmt.Println(a.add(b)) stu := student{"sdsad", 10, "male"} stu.PrintInfo() stu.Rename() fmt.Println(stu) var t test t.index = 101 t.age = 19 t.sex = "male" t.name = "Bbb" t.student.PrintInfo() t.PrintInfo() fmt.Println(t) t.Rename() fmt.Println(t) f1 := t.PrintInfo f2 := t.student.PrintInfo fmt.Printf("%T\\n", f1) fmt.Printf("%T\\n", f2) f1() f2() }
接口的定义和使用:
package main import "fmt" type person struct { name string sex string age int } type student struct { person score int } type teacher struct { person subject string } func (s *student)SayHello(){ fmt.Printf("name: %s, score: %d\\n", s.name, s.score) } func (t *teacher)SayHello(){ fmt.Printf("name: %s, subject: %s\\n", t.name, t.subject) } // 接口的定义 // 接口定义了规则 方法实现了规则 type TestInterface interface { // 方法的声明 没有具体实现 // 接口中定义的方法必须全部有具体的实现 SayHello() } // 多态 type Person interface { SayHello() } // 多态实现 // 多态是将接口类型作为函数参数 func SayHello(p Person){ p.SayHello() } // 接口的继承 type Speaker interface { Person Sing(string) } func (s *student)Sing(name string){ fmt.Printf("Sing %s Name %s\\n", name, s.name) } func main () { var stu student = student{ person{"Bob", "male", 18}, 99 } var tea teacher = teacher{ person{"marry", "male", 28}, "Math" } stu.SayHello() tea.SayHello() // 定义接口类型 var h TestInterface h = &stu h.SayHello() h = &tea h.SayHello() var p Person // 接口 p = &student{ person{"Bob", "male", 18}, 99 } // 多态 SayHello(p) p = &teacher{ person{"marry", "male", 28}, "Math" } SayHello(p) var s Speaker s = &stu s.SayHello() s.Sing("lalala") // 接口的转换 // 将超集转换为子集 p = s p.SayHello() // 不允许子集转换为超集 // s = p // error // 空接口 var i interface{} i = 10 fmt.Println(i) i = "Hello" fmt.Println(i) // 类型断言 if data, ok := i.(string); ok { fmt.Println("string go语言学习笔记 — 基础 — go工具:go工具go语言学习笔记 — 基础 — go工具:一键获取源代码,编译并安装 —— go get
go语言学习笔记 — 基础 — go工具:性能分析,发现代码性能问题的具体位置 —— go pprof
go语言学习笔记 — 基础 — go工具(5.1):单元测试 —— 测试和验证代码的框架