12-Go语言字典和结构体-指趣学院

map(字典、映射)

  • map翻译过来就是字典或者映射, 可以把map看做是切片的升级版
    • 切片是用来存储一组相同类型的数据的, map也是用来存储一组相同类型的数据的
    • 在切片中我们可以通过索引获取对应的元素, 在map中我们可以通过key获取对应的元素
    • 切片的索引是系统自动生成的,从0开始递增. map中的key需要我们自己指定
      • 只要是可以做==、!=判断的数据类型都可以作为key(数值类型、字符串、数组、指针、结构体、接口)
      • map的key的数据类型不能是:slice、map、function
      • map和切片一样容量都不是固定的, 当容量不足时底层会自动扩容

  • map格式:var dic map[key数据类型]value数据类型
package main
import "fmt"
func main() {
    var dic map[int]int = map[int]int{0:1, 1:3, 2:5}
    fmt.Println(dic) // map[0:1 1:3 2:5]

    // 获取map中某个key对应的值
    fmt.Println(dic[0]) // 1
    
    // 修改map中某个key对应的值
    dic[1] = 666
    fmt.Println(dic) // map[0:1 1:666 2:5]
}
package main
import "fmt"
func main() {
    var dict map[string]string = map[string]string{"name":"lnj", "age":"33", "gender":"male"}
    fmt.Println(dict)// map[name:lnj age:33 gender:male]
}

  • 创建map的三种方式
    • 方式一: 通过Go提供的语法糖快速创建
package main
import "fmt"
func main() {
    dict  := map[string]string{"name":"lnj", "age":"33", "gender":"male"}
    fmt.Println(dict)// map[name:lnj age:33 gender:male]
}
  • 方式二:通过make函数创建make(类型, 容量)
package main
import "fmt"
func main() {
    var dict = make(map[string]string, 3)
    dict["name"] = "lnj"
    dict["age"] = "33"
    dict["gender"] = "male"
    fmt.Println(dict)// map[age:33 gender:male name:lnj]
}
  • 方式二:通过make函数创建make(类型)
package main
import "fmt"
func main() {
    var dict = make(map[string]string)
    dict["name"] = "lnj"
    dict["age"] = "33"
    dict["gender"] = "male"
    fmt.Println(dict)// map[age:33 gender:male name:lnj]
}
  • 和切片一样,没有被创建的map是不能使用的
package main
import "fmt"
func main() {
    // map声明后不能直接使用, 只有通过make或语法糖创建之后才会开辟空间,才能使用
    var dict map[string]string
    dict["name"] = "lnj" // 编译报错
    dict["age"] = "33"
    dict["gender"] = "male"
    fmt.Println(dict)
}

  • map的增删改查
    • 增加: 当map中没有指定的key时就会自动增加
package main
import "fmt"
func main() {
    var dict = make(map[string]string)
    fmt.Println("增加前:", dict) // map[]
    dict["name"] = "lnj"
    fmt.Println("增加后:", dict) // map[name:lnj]
}
  • 修改: 当map中有指定的key时就会自动修改
package main
import "fmt"
func main() {
    var dict = map[string]string{"name":"lnj", "age":"33", "gender":"male"}
    fmt.Println("修改前:", dict) // map[name:lnj age:33 gender:male]
    dict["name"] = "zs"
    fmt.Println("修改后:", dict) // map[age:33 gender:male name:zs]
}
  • 删除: 可以通过Go语言内置delete函数删除指定元素
package main
import "fmt"
func main() {
    var dict = map[string]string{"name":"lnj", "age":"33", "gender":"male"}
    fmt.Println("删除前:", dict) // map[name:lnj age:33 gender:male]
    // 第一个参数: 被操作的字典
    // 第二个参数: 需要删除元素对应的key
    delete(dict, "name")
    fmt.Println("删除后:", dict) // map[age:33 gender:male]
}
  • 查询: 通过ok-idiom模式判断指定键值对是否存储
package main
import "fmt"
func main() {
    var dict = map[string]string{"name":"lnj", "age":"33", "gender":"male"}
    //value, ok := dict["age"]
    //if(ok){
    //  fmt.Println("有age这个key,值为", value)
    //}else{
    //  fmt.Println("没有age这个key,值为", value)
    //}
    if value, ok := dict["age"]; ok{
        fmt.Println("有age这个key,值为", value)
    }
}
  • map遍历
    • 注意: map和数组以及切片不同,map中存储的数据是无序的, 所以多次打印输出的顺序可能不同
    var dict = map[string]string{"name":"lnj", "age":"33", "gender":"male"}
    for key, value := range dict{
        fmt.Println(key, value)
    }

结构体

  • Go语言中的结构体和C语言中结构体一样, 都是用来保存一组不同类型的数据
  • Go语言中的结构体和C语言中结构体一样, 都需要先定义结构体类型再利用结构体类型定义结构体变量
  • 定义结构体类型
type 类型名称 struct{
  属性名称 属性类型
  属性名称 属性类型
  ... ...
}
type Studentstruct {
    name string
    age int
}
  • 创建结构体变量的两种方式
    • 方式一: 先定义结构体类型, 再定义结构体变量
      • 和C语言中的结构体一样, 如果结构体类型需要多次使用, 那么建议先定义类型再定义变量
    package main
    import "fmt"
    func main() {
      type Student struct {
          name string
          age int
      }   
    
      // 完全初始化
      var stu1= Student{"lnj", 33}
      fmt.Println(stu1)
      // 部分初始化
      // 部分初始化必须通过 属性名称: 方式指定要初始化的属性
      var stu2 = Student{name:"lnj"}
      fmt.Println(stu2)
    }
    
    • 方式二: 定义结构体类型同时定义结构体变量(匿名结构体)
      • 和C语言中的结构体一样, 如果结构体类型只需要使用一次, 那么建议定义类型同时定义变量
    package main
    import "fmt"
    func main() {
      // 注意: 这里不用写type和结构体类型名称
      var stu2 = struct {
          name string
          age int
      }{
          name: "lnj",
          age: 33,
      }
      fmt.Println(stu2)
    }
    

  • 结构体类型操作
  package main
  import "fmt"
  type Student struct {
      name string
      age int
  }
  func main() {
    var stu= Student{"lnj", 33}
    // 获取结构体中某个属性对应的值
    fmt.Println(stu.name)

    // 修改结构体中某个属性对应的值
    stu.name = "zs"
    fmt.Println(stu)
  }
  • 和slice、map不同的是, 只要定义了结构体变量就可以使用结构体变量
    • 默认情况下结构体中的所有属性都是属性对应类型的默认值
  package main
  import "fmt"
  type Student struct {
      name string
      age int
  }
  func main() {
    var stu Student // 相当于 var stu = Student{}
    fmt.Println(stu) // { 0}
    stu.name = "lnj" // 不会报错
    stu.age = 33
    fmt.Println(stu) // {lnj 33}
  }

  • 复杂结构体成员
    • 创建时可以按照属性单独存在时初始化方式初始化
    package main
    import "fmt"
    type Student struct {
        name string
        age int
    }
    func main() {
      type Demo struct {
          age int // 基本类型作为属性
          arr [3]int // 数组类型作为属性
          sce []int // 切片类型作为属性
          mp map[string]string // 字典类型作为属性
          stu Student // 结构体类型作为属性
      }
    
      var d Demo = Demo{
          33,
          [3]int{1, 3, 5},
          []int{2, 4, 6},
          map[string]string{"class":"one"},
          Student{
              "lnj",
              33,
          },
      }
      fmt.Println(d) // {33 [1 3 5] [2 4 6] map[class:one] {lnj 33}}
    }
    
    • slice、map类型属性默认值是nil,不能直接使用
    package main
    import "fmt"
    type Student struct {
        name string
        age int
    }
    func main() {
      type Demo struct {
          age int // 基本类型作为属性
          arr [3]int // 数组类型作为属性
          sce []int // 切片类型作为属性
          mp map[string]string // 字典类型作为属性
          stu Student // 结构体类型作为属性
      }
    
      // 定义结构体变量
      var d Demo
      // 可以直接使用基本类型属性
      d.age = 33
      // 可以直接使用数组类型属性
      d.arr[0] = 666
      // 不可以直接使用切片类型属性
      //d.sce[0] = 888 // 编译报错
      d.sce = make([]int, 5) // 先创建
      d.sce[0] = 888 // 后使用
      // 不可以直接使用字典类型属性
      //d.mp["class"] = "one" // 编译报错
      d.mp = make(map[string]string)// 先创建
      d.mp["class"] = "one"// 后使用
      // 可以直接使用结构体类型属性
      d.stu.name = "lnj"
      fmt.Println(d) // {33 [666 0 0] [888 0 0 0 0] map[class:one] {lnj 0}}
    }
    

  • 结构体类型转换
    • 属性名、属性类型、属性个数、排列顺序都是类型组成部分
    • 只有属性名、属性类型、属性个数、排列顺序都相同的结构体类型才能转换
  package main
  import "fmt"
  func main() {
    type Person1 struct {
        name string
        age int
    }
    type Person2 struct {
        name string
        age int
    }
    type Person3 struct {
        age int
        name string
    }
    type Person4 struct {
        nm string
        age int
    }
    type Person5 struct {
        name string
        age string
    }
    type Person6 struct {
        age int
        name string
        gender string
    }

    var p1 Person1 = Person1{"lnj", 33}
    var p2 Person2
    // 类型名称不一样不能直接赋值(Person1、Person2)
    //p2 = p1

    // 虽然类型名称不一样, 但是两个类型中的`属性名称`、`属性类型`、`属性个数`、`排列顺序`都一样,所以可以强制转换
    p2 = Person2(p1)
    fmt.Println(p2)
    // 两个结构体类型中的`属性名称`、`属性类型`、`属性个数`都一样,但是`排列顺序`不一样,所以不能强制转换
    //var p3 Person3
    //p3 = Person3(p1)
    //fmt.Println(p3)

    // 两个结构体类型中的`属性类型`、`属性个数`、`排列顺序`都一样,但是`属性名称`不一样,所以不能强制转换
    //var p4 Person4
    //p4 = Person4(p1)
    //fmt.Println(p4)

    // 两个结构体类型中的`属性名称`、`属性个数`、`排列顺序`都一样,但是`属性类型`不一样,所以不能强制转换
    //var p5 Person5
    //p5 = Person5(p1)
    //fmt.Println(p5)

    // 两个结构体类型中的`属性名称`、`属性类型`、`排列顺序`都一样,但是`属性个数`不一样,所以不能强制转换
    //var p6 Person6
    //p6 = Person6(p1)
    //fmt.Println(p6)
  }

  • 匿名属性
    • 没有指定属性名称,只有属性的类型, 我们称之为匿名属性
    • 任何有命名的数据类型都可以作为匿名属性(int、float、bool、string、struct等)
    package main
    import "fmt"
    func main() {
      type Person struct {
          int
          float32
          bool
          string
      }
      // 不指定名称初始化
      per1 := Person{3, 3.14, false, "lnj"}
      fmt.Println(per1)
    
      // 可以把数据类型作为名字显示初始化
      per2 := Person{
          int: 3,
          float32: 3.14,
          bool: true,
          string: "lnj",
      }
      fmt.Println(per2)
    
      // 可以把数据类型当做属性名称操作结构体
      per2.int = 666
      fmt.Println(per2.int) // 666
    }
    
    • Go语言中最常见的匿名属性是用结构体类型作为匿名属性
    package main
    import "fmt"
    func main() {
     type Person struct {
         name string
         age int
     }
     type Student struct {
         Person // 匿名属性
         class string
     }
    
     stu := Student{
         Person{"lnj", 33},
         "学前一班",
     }
     fmt.Println(stu) // {{lnj 33} 学前一班}
    }
    
    • 如果结构体作为匿名属性, 想访问匿名属性的属性有两种方式
    package main
    import "fmt"
    func main() {
      type Person struct {
          name string
          age int
      }
      type Student struct {
          Person // 匿名属性
          class string
      }
    
      stu := Student{
          Person{"lnj", 33},
          "学前一班",
      }
      fmt.Println(stu) // {{lnj 33} 学前一班}
    
      // 方式一: 先找到匿名属性,再访问匿名属性中的属性
      stu.Person.name = "zs"
      fmt.Println(stu) // {{zs 33} 学前一班}
      // 方式二: 直接访问匿名属性中的属性
      // 系统会先查找当前结构体有没有名称叫做name的属性
      // 如果没有会继续查找匿名属性中有没有名称叫做name的属性
      stu.name = "ww"
      fmt.Println(stu) // {{ww 33} 学前一班}
    }
    
    • 注意点: 如果多个匿名属性的属性名称相同,那么不能通过方式二操作,只能通过方式一
    package main
    import "fmt"
    func main() {
      type Person struct {
          name string
          age int
      }
      type Class struct {
          name string
          time string
      }
      type Student struct {
          Person // 匿名属性
          Class // 匿名属性
      }
      stu := Student{
          Person{"lnj", 33},
          Class{"学前一班", "2020-12-12"},
      }
      fmt.Println(stu) // {{lnj 33} {学前一班 2020-12-12}}
      // 编译报错, 系统搞不清楚要找哪个name
      //stu.name = "zs"
    
      stu.Person.name = "zs"
      stu.Class.name = "小学一年级"
      fmt.Println(stu) // {{zs 33} {小学一年级 2020-12-12}}
    }
    
    • 注意点: 只有匿名结构体才支持向上查找
    package main
    import "fmt"
    func main() {
      type Person struct {
          name string
      }
      type Student struct {
          per Person
          age int
      }
    
      var stu Student = Student{Person{"lnj"}, 18}
      //fmt.Println(stu.name) // 报错
      fmt.Println(stu.per.name) // 必须通过属性进一步查找
      fmt.Println(stu.age)
    }
    
    • 注意点: 如果匿名属性是一个结构体类型, 那么这个结构体类型不能是自己
    package main
    import "fmt"
    func main() {
      type Person struct {
          Person // 错误
          name string
      }
      type Student struct {
          *Student  // 正确, 链表
          age int
      }
    }
    
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,905评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,140评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,791评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,483评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,476评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,516评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,905评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,560评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,778评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,557评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,635评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,338评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,925评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,898评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,142评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,818评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,347评论 2 342

推荐阅读更多精彩内容

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,559评论 18 399
  • 昨日,币市所有的币种都上涨10%。这给连日下跌的市场一个好的开端。但牛市未必到来。 我判断基于政策面,还是不明朗。...
    medman阅读 260评论 1 0
  • 纠结的等待 Todywu2016-4-5 或许,遥远的梦就在此刻兑现,望着天空思绪万千,幸福是否来得有些突然!心跳...
    todywu阅读 626评论 0 50