第二章 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
}

  

posted @ 2019-08-06 20:25  现实没有如果  阅读(316)  评论(0编辑  收藏  举报