第二章 Go语言数据类型
一、整数类型
按照长度分为: int8 、int16 、int32 、int64
对应的无符号整型: uint8、uint16、uint32、uint64
获取对象的长度用len()
进制
十进制:
var a int = 10
fmt.Printf("%d \n",a) //10
fmt.Printf("%b \n",a) //1010 占位符%b表示二进制
八进制:
var b int = 077
fmt,Printf("%o \n",c) //ff
十六进制:
var c int = oxff
fmt.Printf("%x \n",c) //ff
fmt.Printf("%X \n",c) //FF
内存地址:
fmt.Printf("%p \n",&a) //0x00004c080 占位符%p表示十六进制的内存地址
注:不同int类型之间不能转换相加减,需要转换成相同类型
interface可以转换任意类型
func test() { var a interface{} //{}表示空的interface var b int = 100 var c float32 = 1.2 var d string = "hello" a = b fmt.Println("a=", a) //100 a = c fmt.Println("a=", a) //1.2 a = d fmt.Println("a=", a) //hello }
二、浮点型
类型:float32和float64 不定义默认是0 浮点数不够精确,可以把浮点数先*100或*1000编程整数进行运算 占位符输出%f
三、布尔类型
类型:True和Flase 默认Flase go语言不能将整型强制转换成布尔型 布尔型无法参与数值运算,也无法与其他类型转换 用%t表示格式化
四、String类型
定义:以原生数据类型出现内部实现使用utf-8
表示字符串:
“ ” //双引号输出会出现转义符的意义
·· //反引号会忽视转义符的意义
字符串常用转义符:
\r:回车符(返回行首) \n:换行符(直接跳到下一行的同列位置) \t:制表符 \':单引号 \":双引号 \:反斜杠
字符串常用方法
+或fmt.Sprintf //拼接字符串 (1) c = c+c fmt.Printf("c = %s\n",c) (2) c = fmt.Sprintf("%s%s",c,c) fmt.Printf("c=%s\n",c) strings.Split //分割 import "strings" func test(){ ip := "10.10.10.1;192.168.1.1" ipArray := strings.Split(ip,";") fmt.Printf("first ip :%s\n",ipArray[0]) fmt.Printf("second ip :%s\n",ipArray[1]) } strings.contains //判断是否包含 import "strings" func test(){ ip := "10.10.10.1;192.168.1.1" result := strings.Contains(ip,"10.10.10.1") fmt.Println(result) //返回布尔值 } strings.HasPrefix/HasSuffix //判断前缀和后缀 import "strings" func test(){ str := "https://www.baidu.com" if strings.HasPrefix(str,"http"){ fmt.Println("str is http url") }else{ fmt.Println("str is not http url") } var last bool last = strings.HasSuffix(str,"com") fmt.Printf(last) //返回bool } strings.Index()/LastIndex() //子串出现的位置 import "strings" func test(){ str := "https://www.baidu.com" index := strings.Index(str,"baidu") //baidu第一次出现的位置 fmt.Printf("str is index:%d\n",index) index = strings.LastIndex(str,"baidu") //baidu最后一次出现的位置 fmt.Printf("baidu last index:%d\n",index) } strings.Join(a[]string,sep string) //join操作,把一个数组每一个元素根据分隔符为基准重新组成字符串 func test(){ var strArr []string = []string{"10.10.10.1","11.11.11.2","12.12.12.3"} resultStr = strings.Join(strArr,";") fmt.Printf("result=%s\n"mresultStr) //输出result=10.10.10.1;11.11.11.2;12.12.12.3 }
五、字符类型
定义:组成字符串的元素叫做字符,字符用' '表示,分别有uint8(byte)类型,代表一个ASCII码的字符;rune类型,代表一个UTF-8字符
package main import "fmt" func main(){ s1 := "Golang" c1 := 'G' fmt.Println(s1,c1) //Golang 71 字符的编码 s2 := "中国" c2 := '中' //汉字表示3位 fmt.Println(s2,c2) //中国 20013 s3 := "Go语言" fmt.Println(len(s3)) //11 一个字符1字节,中文3字节 for i := 0;i<len(s3);i++{ //bytes中文乱码 fmt.Printf("%c\n",s3[i]) //%c打印字符 } for k,v := range s3{ //可打印中文字符 fmt.Printf("%d,%c\n",v) //k表示字节的索引数 } }
强制转换字符串和utf-8
func main(){ s1 := "big" bytes1 := []byte(s1) //将字符串强制转换成字节数组类型 fmt.Println(bytes1) //[98 105 103]分别对应了各自的字符 bytes1[0] = 'p' fmt.Println(string(bytes1)) //[112 105 103] s1 = string(bytes1) //将字节数组强制转换成字符串类型 fmt.Println(s1) s2 := "大白菜" runes2 := []rune(s2) runes2[0] ='小' fmt.Println(string(runes2),len(runes2)) } //只有强制类型转换,不能重新赋值
字符串反转操作
//英文 func main(){ s1 := "hello" byteArray := []byte(s1) //[h e l l o] //方法1 s2 := "" for i :=len(byteArray)-1;i>=0;i--{ s2 = s2 + string(byteArray[i]) //byteArray[i] --> o l l e h } fmt.Println(s2) //方法2 for i := 0;i<len(byteArray)/2;i++{ byteArray[i],byteArray(len(byteArray)-1-i) = byteArray(length-1-i),byteArray[i] } fmt.Println(string(byteArray)) } //中文 func main(){ str := "中文" r []rune := []rune(str) for i := 0;i<len(r)/2;i++{ tmp := r[len(str)-i-1] r[len(str)-i-1] = r[i] r[i] = tmp } fmt.Println(string(r[i])) }
六、指针
变量和内存地址:每个变量都有内存地址,通过变量来操作对应大小的内存;普通变量存储的是对应类型的值,这些类型就叫做值类型
func main(){ var a int32 a = 100 fmt.Printf("the addr of a:%p",&a) //the addr of a:0x000062058 }
指针类型:指针类型的变量存储的是一个地址,所以又叫指针类型或引用类型;操作指针变量指向地址里的值
func test(){ var a int32 a = 156 fmt.Printf("the addr of b:%p,b:%v\n",&b,b) if b == nil{ fmt.Println("这个指针变量为空") } b = &a //将a变量地址传到b中 fmt.Printf("the addr of b:%p,b:%v\n",&b,b) //b的内容为a的地址,但b的内存地址与a不同 } func test2(){ var a int = 200 var b *int = &a fmt.Printf("b指向的地址存储的值为:%d\n",*b) //打印b中存储的内存地址所存的数值 *b = 1000 //修改b存的内存地址所存得数值 fmt.Printf("b指向的地址存储的值为:%d\n",*b) fmt.Printf("a=%d\n",a) }
指针传参
func modify(a *int){ *a = 100 } func testvariable(){ var b int = 10 p := &b modify(p) fmt.Printf("b:%d\n",b) //b:100 } //在p定义一个指针变量,把p传入modify中a会拷贝一份b的内存地址在自己的值中,a就可以操作b的值 //数组 func modify(a *[3]int){ (*a)[0] = 100 } func testvariable(){ var b [3]int = [3]int{1,2,3} modify(&b) fmt.Println(b) //[100,2,3] }
make和new的区别:
make用来分配引用类型的内存,比如map,slice以及channel
new用来分配除引用类型的所有其他类型的内存,比如int和数组
func testvariable(){ var a *int = new(int) *a = 100 fmt.Printf("*a=%d\n",*a) //整型可以直接操作 var b *[]int = new([]int) fmt.Printf("*b = %v\n",*b) (*b) = make([]int,5,10) //切片只有make后才能进行操作,否则报错 (*b)[0] = 100 (*b)[1] = 200 fmt.Printf("*b = %v\n",*b) }
值拷贝和引用拷贝
//值拷贝 func modify(){ a = 100 } func testvariable(){ var b int = 10 modify(b) fmt.Printf(*b=%d\n",b) } //b的值不变,调用modify函数是会把值拷贝过去一份,但是内存地址不一样 //引用拷贝 func testvariable(){ var a int = 10 var b *int = &a var c *int = b *c = 200 fmt.Printf("*c=%d *b=%d a=%d\n",*c,*b,a) } //a的内存地址都拷贝到b和c中,所以一个操作都会修改
七、Array数组
定义:表示同一种数据类型的集合,数组长度从声明的时候就确定了,使用时可以修改数组成员,但是数组大小不可变化
var a [3] int //定义一个数组,数组下标从0开始,因此长度为n的数组下标范围:[0,n-1];
整数数组中的元素默认初始化为0,字符串数组中的元素默认初始化为""
数组初始化:不同数组的长度和类型不同,则不能直接赋值
func test(){ a := [3]int{1,2,3} b := [5]int b = a //不成立 } func test2(){ var a [3] int //定义一个长度为3的int型数组 a[0] = 10 //分别给数组中的位置传值 a[1] = 20 a[2] = 30 //方法2 var a [3]int = [3]int{10,20,30} //方法3 a := [3]int{10,20,30} //方法4 a := [...]int{10,20,30} //...表示任意长度,由传入的参数决定 //方法5 a := [3]int{10} //10,0,0 //方法6 a := [3]int{2:10} //索引为2的元素初始值换成10
数组遍历
func testArray(){ a := [5]int{3:100,4:300} for i:=0;i<len(a);i++{ fmt.Printf("a[%d]=%d\n",i,a[i]) //打印索引位和该索引位的数值 } } func testArray(){ a := [3]int{1,2,3} for index,value := range a{ //range会返回两个数,第一个为range的下标,第二个是值 fmt.Printf("a[%d]=%d\n",index,value) //当不需要index时可以用_代替 } }
二维数组
func testArray(){ var a [3][2]int a[0][0] = 10 a[0][1] = 20 a[1][0] = 30 a[1][1] = 40 a[2][0] = 50 a[2][1] = 60 fmt.Println(a) //[[10 20] [30 40] [50 60]] for i :=0;i<3;i++{ for j:=;j<2;j++{ fmt.Printf("%d",a[i][j] //10 20 30 40 50 60 } for i,val1 := range a{ for k,val2 :=range bal1{ fmt.Printf("(%d,%d)=%d",i,j,val2) //(0,0)=10 (0,1)=20....... } } }
数组拷贝和传参
//拷贝 func testArray(){ var a [3]int a[0] = 10 a[2] = 20 a[3] = 30 b := a //b拷贝了数组a总所有的元素 b[0] = 1000 fmt.Println(a,b) //[10,20,30] [1000,20,30] //拷贝的值相同,内存地址不同 } //传参 func testArray(){ a := [3]int{10,20,30} modify(a) //当一个数组作为参数传递时,会将值拷贝一份过去 fmt.Println(a) //[10 20 30] } func modify(b [3]int){ b[0] = 1000 //修改此处的值不影响原数据 return }
八、Slic切片
定义:是基于数组类型作的一层封装,可以自动扩容 var a []int //定义一个int类型的切片
//初始化切片 func test(){ a := [5]int{1,2,3,4,5} var b []int = a[1:4] fmt.Println(b) //[2 3 4] } func test2(){ a := []int{1,2,3} fmt.Println(a) } //切片的基本操作 functest(){ a := []int{1,2,3,4,5,6,7,8} var b []int = a[2:6] //下标从2到6的元素,不包括6 fmt.Println(b) //[3 4 5 6] var c []int = a[3:] //从下标为3的元素到最后元素,包括3 fmt.Println(c) //[4 5 6 7 8] var d []int = a[:5] //下标为0的元素到下标5的元素,包括0但不包括5 fmt.Println(d) //[1 2 3 4 5] var e []int = a[:] //包括这个数组的所有元素 fmt.Println(e) //[1 2 3 4 5 6 7 8] //修改切片:切片的修改是对应数组的,改的是数组的内存地址 func test(){{ a := [..]int{1,2,3,4,5,6,7,8} b := a[2:5] b[0] = b[0] + 10 b[1] = b[1] + 10 b[2] = b[2] + 10 fmt,Println(a) //[1,2,13,14,15,6,7,8} darr := [...]int{1,2,3,4,5,6} dslice := darrr[2:5] fmt.Println(“array before”,darr) //{1,2,3,4,5,6} for i,v:= range dslice{ dslice[i]++ fmt.Println(i,v) //获取到下标i和值v,修改数据要用切片对应的下标进行修改 } fmt.Println("arraty after",darr) //[1,2,4,5,6,6} } //make创建切片 func test(){ a := make([]int,5,10) //5表示长度,10 表示容量,容量从0开始 a[0] = 10 a[1] = 20 a = append(a,30) //长度表示显示长度,容量表示内存容量,切片可以通过append添加,当容量不足时,append还可以对属于组进行扩容,当append扩容的时候,底层为新建一个双倍容量的内存空间,把之前的数组内容拷贝进去 fmt.Println(a) //[10,20,0,0,0,30] } func test2(){ a := make([]intt,0,10} fmt.Println(b,len(b),cap(b)) b = append(b,100) fmt.Println(b,len(b),cap(b)) //无长度,添加到数组的第一个位置 } //切片再切片 func test(){ a := [...]string{"a","b","c","d","e","f"} b := a[1:3[ fmt.Println(b,len(b),cap(b)) //[b,c]长度2,容量5 [b c] 2 5 b = b[:cap(b)] fmt.Println(b,len(b),cap(b)) //这样切片会让长度=容量==5 [b c d e f] 5 5 } //空切片和扩展策略 func testnil() { var a []int fmt.Println(a, len(a), cap(a)) if a == nil { fmt.Println("a is nil") } a = append(a, 100) fmt.Printf("%d,%p,len:%d,cap%d\n", a, a, len(a), cap(a)) //[100],0xc0000100a8,len:1,cap1 %p表示内存地址 a = append(a, 200) fmt.Printf("%d,%p,len:%d,cap%d\n", a, a, len(a), cap(a)) //[100 200],0xc000010100,len:2,cap2 a = append(a, 300) fmt.Printf("%d,%p,len:%d,cap%d\n", a, a, len(a), cap(a)) //[100 200 300],0xc00000a400,len:3,cap4 a = append(a, 400) fmt.Printf("%d,%p,len:%d,cap%d\n", a, a, len(a), cap(a)) //[100 200 300 400],0xc00000a400,len:4,cap4 a = append(a, 500) fmt.Printf("%d,%p,len:%d,cap%d\n", a, a, len(a), cap(a)) //[100 200 300 400 500],0xc00000e280,len:5,cap8 } //切片传参 func test(){ a := []int{1,2,3} b := []int{4,5,6} a = append(a,23,34,45) fmt.Println(a) //[1,2,3,,23,34,45] a = append(a,b...) fmt.Println(a) //[1,2,3,23,34,45,4,5,6] } func test2(){ var a []int = []int{1,2,3} var b []iont = []int{4,5,6} vvopy(a,b) fmt.Println(a) //[4,5,6] fmt.Println(b) //[4,5,6] var c []int = []int{1,2} var d []int = []int{4,5,6} copy(c,d) fmt.Println(c) //[4,5] fmt.Println(d) //[4,5,6] }
九、Map哈希表
定义:map类型是一个key-value的数据结构
声明:var a map[key的类型]value类型。如:var a map[string]int var b map[int]string var c map[float32]string
//初始化 map必须初始化才能使用 func test(){ var a map[string]int fmt.Pringf("a:%v\n",a) if a == nil{ //根据是否为空判断有没有初始化 a = make(map[string]intm,16) //初始化map并定义容量16 fmt.Printf("a=%v\n",a) a["stu01"]=1000 fmt.Printf("a=%v\n",a) //a = map【sttu01:1000] } } func test2(){ a := map[string]int "steve":12000, //逗号要加 "jamie":15000 } a["mike"] = 9000 fmt.Println("a map contents:",a) } //map插入操作 func test(){ a := make(map[string]int) a["steve"] = 12000 a["jamie"] = 15000 a["mike"] = 9000 fmt.Println("a map contents:",a) //a map contents:map[jamie:15000 mike:9000 steve:12000] } //通过key访问map中的元素 func test(){ a := map[string]int{ "steve":12000, "jamie":15000 } a["mike"] = 9000 b := "jamie" fmt.Println("Salary of",b,"is","a[b]) //Salary of jamie is 15000 } //判断map指定的key是否cunzai func test() { a := map[string]int{ "stu01": 1000, "stu02": 2000, } b := "joe" value,ok := a[b] //valuesahib值,ok是布尔类型 if ok == false { fmt.Printf("key %s is not exisst\n",b) } else{ fmt.Printf("key %s is %d\n",b,value) } } //遍历map func test() { a := map[string]int{ "stu01": 1000, "stu02": 2000, } fmt.Println("all items of a map") for key,value := range a{ fmt.Printfd("["[%s]=%d\n",key,value) } } //map删除元素 func test() { a := map[string]int{ "stu01": 1000, "stu02": 2000, } fmt.Println("map before deletion",a) delete(a,"steve") fmt.Println("map after deletion",a) } //map的长度 func testmap() { a := map[string]int{ "stu01": 1000, "stu02": 2000, } fmt.Println("length is", len(a)) } //map是引用类型 func testmap() { a := map[string]int{ "stu01": 1000, "stu02": 2000, } fmtPrintln("origin map",a) b := a //b引用了a的内存地址 b["steve"] = 1800 //b变了,a也变了 fmt.Println("a map changed",a) } //map排序 func test() { var a map[string]int = make(map[string]int, 10) for i := 0; i < 10; i++ { key := fmt.Sprintf("key%d", i) a[key] = i } var keys []string = make([]string, 0, 10) for key, value := range a { fmt.Printf("key:%s = %d\n", key, value) //默认是无序的 keys = append(keys, key) //将map添加到数组中 } sort.Strings(keys) //将数组排序 for _, value := range keys { fmt.Printf("key:%s val:%d\n", value, a[value]) } } //map类型的切片 func test() { var mapSlice []map[string]int //定义一个切片中是map mapSlice = make([]map[string]int, 3, 10) //初始化切片 fmt.Println("before map init") for index, value := range mapSlice { //遍历切片中的map fmt.Printf("index:%d value:%v\n", index, value) } fmt.Println() mapSlice[0] = make(map[string]int, 10) //初始化map mapSlice[0]["a"] = 1000 mapSlice[0]["b"] = 2000 fmt.Println("after map init") for index, value := range mapSlice { //遍历切片中的map fmt.Printf("index:%d value:%v\n", index, value) } } func test() { var s map[string][]int //定义一个map中是切片 s = make(map[string][]int, 16) //初始化map key := "stu01" //定义一个键 value, ok := s[key] //判断该键的切片是否存在 if !ok { //如果不存在则初始化该键对应的切片 s[key] = make([]int, 0, 16) } value = append(value, 100) value = append(value, 200) s[key] = value //将value赋值s[key] fmt.Printf("map:%v\n", s) }
十、Struct结构体
定义:go中面向对象时通过struct来实现的
//struct初始化方法 type User struct { Username string Sex string Age int AvatarUrl string } func test(){ //方法一 var user User user.Age = 18 user.Username = "user01" user.Sex = "男" user.AvatarUrl = "www.baidu.com" //方法二 var user User = User{ Username : "user01" Age : 18 Sex : "男" AvatarUrl : www.baidu.com } //方法三 user := User{ Username : "user01" Age : 18 Sex : "男" AvatarUrl : www.baidu.com } fmt.Printf("user.name=%s age=%d sex=%s avatar=%s\n", user.Username, user.Age, user.Sex, user.AvatarUrl) } //结构体类型的指针 var user *User = &User{} fmt.Printf("%p %#v\n",user) var user *User = &User{ Username : "user01" Age : 18 Sex : "男" AvatarUrl : www.baidu.com } var user User = new(User) Username = "user01" Age = 18 Sex = "男" AvatarUrl = www.baidu.com func test() { var user *User fmt.Printf("user=%v\n", user) //user=<nil> var user01 *User = &User{} user01.Age = 18 user01.Username = "user01" fmt.Printf("user01=%#v\n", user01) //user01=&main.User{Username:"user01", Sex:"", Age:18, AvatarUrl:""} }
struct如何被函数返回
package main import "fmt" type Student struct { Name string Age int } func (stu Student) NewStudent() *Student{ var s1 = new(Student) s1.Name = "张三" s1.Age = 18 return s1 } func main() { var stu = new(Student) stu = stu.NewStudent() fmt.Println(stu) }
struct的内存布局以及构造函数
//结构体的内存布局:占用一段连续的内存空间 type Test struct{ A int32 B int32 C int32 D int32 } func test(){ var t Test fmt.Printf("a addr:%p\n", &t.A) a addr:0xc000062070 fmt.Printf("b addr:%p\n", &t.B) b addr:0xc000062074 fmt.Printf("c addr:%p\n", &t.C) c addr:0xc000062078 fmt.Printf("d addr:%p\n", &t.D) d addr:0xc00006207c } //每块占用4字节,在内存中连续 //无构造函数,需要自己定义 import "导入user包" func main(){ var u user.User u.Age = 18 fmt,Printf("user.%#v\n",u) } package user type User struct{ Username string Sex string Age int AvatarUrl string }
匿名字段和struct嵌套
//匿名字段:没有定义名字的字段 type User struct{ Username string Sex string Age int AvatarUrl string int //匿名字段 string //匿名字段 } func main(){ var u User u.Username = "user01" u.Sex = "man" u.int = 100 u.string = "hello" fmt.Printf("user=%#v\n“,u”) } //匿名字段默认采用类型名作为字段名 type Address struct{ Province string City string } type User struct{ Username string Sex string &Address } func test()[ var user User user.Username = "user" user.Sex = "man" user.Address = &Address{ //第一种方式 Province : "北京", City : "北京", } user.Province = "北京" //第二种方式 user.City = "北京" } //匿名字段冲突 type Address struct{ Province string City string } type User struct{ City string Username string Sex string *Address } func test()[ var user User user.Username = "user" user.Sex = "man" user.City = "北京" fmt.Printf("user=%#v\n",user) user.Address = new(Address) //指针必须初始化 fmt.Printf("user=%#v\n",user) user.Address.City = "北京" fdmt.Printf("user=%#v city of address:%s\n",user,user.Address.City)
结构体链表
单链表定义:每个节点包含下一个节点的地址,这样把所有的节点串起来叫做单链表,第一个节点叫做链表头
双链表定义:如果两个指针分别指向前一个节点和后一个节点,就是双链表
//单链表 type Studfent struct()[ Name string Next *Student } //双链表 type Student struct{ Name string Next *Student Preve *Student }
结构体二叉树
定义:如果每个节点有两个指针分别用来是想左子树和柚子树,这样的结构就是二叉树
type Student struct{ Name string Age int Score float64 Left *Student Right *Student } func trans(root *Student){ if root == nil{ return } fmt.Println(root) //前序遍历 trans(root.Left) trans(root.Right) } func main(){ var root *Student = new(Student) root.Name = "stu01" root.Age = 19 root.Score = 100 var left1 *Student = new(Student) left1.Name = "stu02" left1.Age = 19 ledt1.Score = 100 root.Left = left1 var rigtht1 *Student = new(Student) right1.Name = "stu04" right1.Age = 19 right1.Score = 100 root.Right = right1 var left2 *Student = new(Student) left2.Name = "stu02" left.Age = 19 left.Score = 100 left2.Score = 100 left1.left = left2 trans(root) } //&{stu01 19 100 0xc000078330 0xc000078360} //&{stu02 19 100 0xc000078390 <nil>} //&{stu03 19 100 <nil> <nil>} //&{stu04 19 100 <nil> <nil>} func trans(root *Student){ if root == nil{ return } trans(root.left) fmt.Println(root) //中序遍历 trans(root.right) } //&{stu03 19 100 <nil> <nil>} //&{stu02 19 100 0xc000078390 <nil>} //&{stu01 19 100 0xc000078330 0xc000078360} //&{stu04 19 100 <nil> <nil>} func trans(root *Student){ if root == nil{ return } trans(root.left) trans(root.right) fmt.Println(root) //后序遍历 } //&{stu03 19 100 <nil> <nil>} //&{stu02 19 100 0xc000078390 <nil>} //&{stu04 19 100 <nil> <nil>} //&{stu01 19 100 0xc000078330 0xc000078360}
工厂模式
定义:golang中struct没有构造函数,可以用工厂模式来解决这个问题
//简单工厂模式 package easyfactory import "errors" type operation struct{ } type cal interface( cal(int,int) (float64,error) } type operationAdd struct{ operation } func (o *operationAdd) cal(num1,num2 int) (float64,error) { return float64(num1+num2),nil } type operationMinus struct { operation } func (o *operationMinus) cal(num1,num2 int) (float64,error) { return floaf64(num1-num2),nil } type operationMulti struct { operation } func (o *operationMulti) cal(num1,num2 int) (float,errror) { return float64(num1 * num2),nil } type operationDiv struct{ operation } func (o *operationDiv) cal(num1,num2 int) (float64,error) { if num2 == 0{ return 0,errors.New("除法运算中除数不能为0") } return float64(num1/num2),nil } type operationFactory struct{} func (o *operationFactory) createOperation(op string) cal { switch op{ case "+": return new(operationAdd) case "-": return new(operationMinus) case "*": return new(operationMulti) case "/": return new(operationDiv) } return nil }
struct和tag应用
定义:tag是结构体的原信息,可以运行的时候通过反射的机制读取出来,字段类型后面,以反引号的key:value结构的字符串,多了tag以逗号隔开
type User struct{ Username string `json:"username"` Sex string `json:"sex"` Score float32 } func main(){ user := & User { Username:"user01", Sex:"男", Score: 84, } data,_ := json.Marshal(user) //第二个接收的数据是错误,为nil fmt.Printf("json str:%s\n",string(data)) }
方法
定义:go的方法是在函数面前加上一个接收者,这样编译器就知道这个方法属于哪个类型
type A struct{ } func (a A) Test(s string){ //通过a来访问A的实例中的成员变量,也就是struct的字段 } func main(){ var t A t.Test() //调用方法 } type People struct{ Name string Country string } func (p People) Print() { fmt.Printf("name=%s country=%s\n",p.Name,p.Country) } func (p People) Set(name,country string) { p.Name = name p.Country = country } func test() { var p1 People = People{ Name : "pe01", Country : "china", } p1.Print() //pe01 china p1.Set("pe02","Ch") p1.Print() //pe01 china Set修改的数据通过值拷贝传出,原地址数据不变 } //可以为当前包内定义的任何类型增加方法 type Integer int //创建Integer为int的别名 func (i Integer) Print() { fmt.Println(i) } func test() { var a Integer //设定一个变量为Integer类型 a = 1000 a.Print() //调用int自定义的Print方法 var b int = 200 a = Integer(b) a.Print() }
值类型和指针类型
type People struct { Name string Country string } func (p People) Print() { fmt.Printf("name=%s country=%s\n",p.Name,p.Country) } func (p *People Set(name,country string) { p.Name = name p.Country = country } func test() { var p1 People = People{ Name:"pe01", Country:"china", } p1.Print() (&p1).Set2("pe02","Ch") //指针地址内容改变,所以数据改变,也可以写成p1.Set("pe02","Ch") p1.Print() }
匿名字段和继承
type Animal struct{ Name string Sex string ) func (a *Animal) Talk() { fmt.Printf("i,talk,i'm %s\n",a.Name) } type Dog struct{ Feet string *Animal //或者Animal 通过组合来实现继承 } func (d *Dog)Eat() { fmt.Println("dog is eat") } func test() { var d *Dog &Dog{ Feet:"four feet", Animal:&Animal{ Name:"dog", Sex:"xiong" }, } d.Eat() d.Talk() }
多重继承与冲突解决
type Dog struct{ Feet string *Animal1 *Animal2 } type Animal1 struct { Name string Sex string } func (a *Animal1) Talk(){ fmt.Printf("i,talk,i'm %s\n",a.Name) } type Animal2 struct { Name string Sex string } func (p *Animal2) Talk(){ fmt.Println("Animal2") } func test() { var d *Dog = &Dog{ Feet:"four feet", Animal1:&Animal1{ Name:"dog", Sex:"xiong", }, } d.Animal1.Talk() d.Animal2.Talk() }
结构体和Json序列化
//序列化 struct转json import "encoding/json" type Student struct{ Id int Name string Sex string } type Class struct{ Name string Count int Student []*Student } func test(){ c := &Class{ Name:"101", Count:0, } for i:= 0,i<10;i++{ stu := &Student{ Name :fmt.Sprintf("stu%d",i), Sex :"man", Id:i, } c.Student = append(c.Student,stu) } data,err := json.Marshal(c) if err != nil{ fmt.Println("json marashal failed") return } fmt.Printf("json:%s\n",string(data)) } //反序列化 json装struct type Student struct{ Id int Name string Sex string } type Class struct{ Name string Count int Student []*Student } var rawJson = `{"Name":"101","Count":0,"Student":[ {"Id":0,"Name":"stu0","Sex":"man"},{"Id":1,"Name":"stu1","Sex":"man"}, {"Id":2,"Name":"stu2","Sex":"man"},{"Id":3,"Name":"stu3","Sex":"man"}, {"Id":4,"Name":"stu4","Sex":"man"},{"Id":5,"Name":"stu5","Sex":"man"}, ] }`rint var c1 *Class = &Class{} err := json.Unmarshal([]byte(rawJson),c1) if err != nil{ fmt.Println("unmarshal failed") return } fmt.Printf("c1:%#v\n",c1) /*c1:&main.Class{ Name:"101", Count:0, Student:[]*main.Student{ (*main.Student)(0xc00007a510), (*main.Student)(0xc00007a540), (*main.Student)(0xc00007a570), (*main.Student)(0xc00007a5a0), (*main.Student)(0xc00007a600), (*main.Student)(0xc00007a630), }*/ for _,v := range c1.Student{ fmt.Printf("stu:%#v\n",v) /*stu:&main.Student{Id:0, Name:"stu0", Sex:"man"} stu:&main.Student{Id:1, Name:"stu1", Sex:"man"} stu:&main.Student{Id:2, Name:"stu2", Sex:"man"} stu:&main.Student{Id:3, Name:"stu3", Sex:"man"} stu:&main.Student{Id:4, Name:"stu4", Sex:"man"} stu:&main.Student{Id:5, Name:"stu5", Sex:"man"}*/ } }
十一、时间和日期
使用time包中的time.Time类型用来表示时间
获取当前时间:
now := time.Now() 获取当前时间
now := time.Now().Day()
now := time.Now().Minute()
now := time.Now().Month()
now := time.Now().Year()
格式化:
func main(){ now := time.Now() fmt.Printf("current time:$v\n",now) tear := now.Year() month := now.Month() day := now.Day() hour := now.Hour() minute := now.Minute() send := now.Second() fmt.Printf("%02d-%02d-%02d-%02d-%02d-%02d", year, month, day, hour, minute, send) }
定时器
func main(){ ticker := time.Tick(5*time.Second) //每5s执行一次其中的函数 for i := range ticker{ fmt.Printf("%v\n",i) 函数() } }
格式化
func main(){ now := time.Now() fmt.Println(now.Format("02/1/2006 15:04")) fmt.Println(now.Format("2006/1/02 15:04")) fmt.Println(now.Format("2006/1/02")) } //格式可以换,时间必须为2006 1 02 15:04
计算程序运行时间
func main(){ start := time.Now().UnixNano() for i := 0;i<10;i++{ time.Sleep(time.Millisecond) } end := time.Now().UnixNano() cost := (end - start)/1000000 //微秒化成秒 fmt.Printf("%vn",cost) }
十二、if-else
//分支结构 func main(){ age := 19 if age >18{ fmt.Println("澳门赌场") }else if age <18{ fmt.Println("Waring...") }else{ fmt.Println("成年了") } } //特殊写法 func main(){ age := 18 if age ==18{ fmt.Println("成年”) } if age2 := 28;age2 >18{ fmt.Println("成年了") } fmt.Println(age2) //报错,在判断条件中定义变量无法在判断条件外打印 }
十三、switch-case
定义:用于if条件多时
//每个switch只能有一个default分支 func test(){ t:=3 switch t{ case 1 : //如果条件t是1则执行 fmt.Println("大拇指") case 2 : //如果条件t是2则执行 fmt.Println("食指") default: //否则输出 fmt.Println("无效的输入") } //一个分支可以有多个值,之间用逗号分隔 func test2(){ switch t := 7;t{ case 1,3,5,7,9: fmt.Println("奇数") case 2,4,6,8: fmt.Println("偶数") default: fmt.Println(n) } } //分支可以使用表达式,此时switch后不需要再跟判断变量 func test3(){ age :=30 switch { case age <25: fmt.Println("好好学习") case age >25: fmt.Println("好好工作") case age >60: fmt.Println("活着真好") } } //fallthrough语法可以执行满足条件的case的下一个case,是为了兼容c语言中的case设计的 func test4(){ s := "a" switch{ case s == "a" : //成立 fmt.Println("a") fallthrough //无条件的执行下一个case语句 case s =="b": fmt.Println("b") case s=="c": fmt.Println("c") default: fmt.Println("...") } }
十四、for
//for循环 for 初始语句;条件表达式;结束语句{ 循环体语句 } func test(){ a := 3 for i := 0;i<a;i++{ //定义i=0,如果i<a,则成立执行循环,循环结束后i++ fmt.Println(i) } } //无线循环 for { 循环体语句 } //可以通过break,goto,return,panic强制退出
for range:键值循环
数组:返回索引和值 切片:返回索引和值 字符串:返回索引和值 map:返回键和值 通道(channel):只返回通道内的值
十五、goto/continue/break
break:退出当前循环,后加标签直接退出到标签处
continue:返回执行下一次循环,后加标签循环下一次的标签处
goto:通过标签进行代码间的无条件跳转,可以快速跳出循环,避免重复退出
//goto func test(){ for i := 0;i<5;i++{ for j:=0;j<3;j++{ if i == 2 && j == 2{ goto yhc //直接跳转到yhc } } } fmt.Println("两层for循环结束") yhc : //定义一个标签label }