Go基础:指针、Map、结构体

简介: Go基础:指针、Map、结构体

 Map

Go语言中的map是引用类型,必须初始化才能使用,是一种无序的基于key-value的数据结构

func main() {
    scoreMap := make(map[string]int, 8)
    scoreMap["张三"] = 90
    scoreMap["小明"] = 100
    fmt.Println(scoreMap)
    fmt.Println(scoreMap["小明"])
    fmt.Printf("type of a:%T\n", scoreMap)
}

image.gif


image.gif

Go语言中使用for range遍历map

func main() {
    scoreMap := make(map[string]int)
    scoreMap["张三"] = 90
    scoreMap["小明"] = 100
    scoreMap["王五"] = 60
    for k, v := range scoreMap {
        fmt.Println(k, v)
    }
}

image.gif


image.gif

按照指定顺序遍历map

func main() {
    rand.Seed(time.Now().UnixNano()) //初始化随机数种子
    var scoreMap = make(map[string]int, 200)
    for i := 0; i < 100; i++ {
        key := fmt.Sprintf("stu%02d", i) //生成stu开头的字符串
        value := rand.Intn(100)          //生成0~99的随机整数
        scoreMap[key] = value
    }
    //取出map中的所有key存入切片keys
    var keys = make([]string, 0, 200)
    for key := range scoreMap {
        keys = append(keys, key)
    }
    //对切片进行排序
    sort.Strings(keys)
    //按照排序后的key遍历map
    for _, key := range keys {
        fmt.Println(key, scoreMap[key])
    }
}

image.gif


image.gif

元素为map类型的切片

func main() {
    var mapSlice = make([]map[string]string, 3)
    for index, value := range mapSlice {
        fmt.Printf("index:%d value:%v\n", index, value)
    }
    fmt.Println("after init")
    // 对切片中的map元素进行初始化
    mapSlice[0] = make(map[string]string, 10)
    mapSlice[0]["name"] = "王五"
    mapSlice[0]["password"] = "123456"
    mapSlice[0]["address"] = "红旗大街"
    for index, value := range mapSlice {
        fmt.Printf("index:%d value:%v\n", index, value)
    }
}

image.gif

值为切片类型的map

func main() {
    var sliceMap = make(map[string][]string, 3)
    fmt.Println(sliceMap)
    fmt.Println("after init")
    key := "中国"
    value, ok := sliceMap[key]
    if !ok {
        value = make([]string, 0, 2)
    }
    value = append(value, "北京", "上海")
    sliceMap[key] = value
    fmt.Println(sliceMap)
}

image.gif

结构体

Go语言中没有“类”的概念,也不支持“类”的继承等面向对象的概念

Go语言中通过结构体的内嵌再配合接口比面向对象具有更高的扩展性和灵活性。

类型定义和类型别名的区别

类型别名与类型定义表面上看只有一个等号的差异

//类型定义
type NewInt int
//类型别名
type MyInt = int
func main() {
    var a NewInt
    var b MyInt
    fmt.Printf("type of a:%T\n", a) //type of a:main.NewInt
    fmt.Printf("type of b:%T\n", b) //type of b:int
}

image.gif

struct

Go语言中通过struct来实现面向对象


image.gif

取结构体的地址

type student struct {
    name string
    age  int
}
func main() {
    m := make(map[string]*student)
    stus := []student{
        {name: "pprof.cn", age: 18},
        {name: "测试", age: 23},
        {name: "博客", age: 28},
    }
    for _, stu := range stus {
        m[stu.name] = &stu
    }
    for k, v := range m {
        fmt.Println(k, "=>", v.name)
    }
}

image.gif

结构体没有构造函数,可自己实现

Go语言的结构体没有构造函数,我们可以自己实现。 例如,下方的代码就实现了一个person的构造函数。 因为struct是值类型,如果结构体比较复杂的话,值拷贝性能开销会比较大,所以该构造函数返回的是结构体指针类型

image.gif

func newPerson(name, city string, age int8) *person {
    return &person{
        name: name,
        city: city,
        age:  age,
    }
}

image.gif

调用构造函数

p9 := newPerson("pprof.cn", "测试", 90)
fmt.Printf("%#v\n", p9)

image.gif

方法和接收者

Go语言中的方法(Method)是一种作用于特定类型变量的函数。这种特定类型变量叫做接收者(Receiver)。接收者的概念就类似于其他语言中的this或者 self。

image.gif

方法的定义格式如下:

func (接收者变量 接收者类型) 方法名(参数列表) (返回参数) {
        函数体
    }

image.gif

其中,

    • 接收者变量:接收者中的参数变量名在命名时,官方建议使用接收者类型名的第一个小写字母,而不是self、this之类的命名。例 如,Person类型的接收者变量应该命名为 p,Connector类型的接收者变量应该命名为c等。
    • 接收者类型:接收者类型和参数类似,可以是指针类型和非指针类型。
    • 方法名、参数列表、返回参数:具体格式与函数定义相同。

    举个例子:

    //Person 结构体
    type Person struct {
        name string
        age  int8
    }
    //NewPerson 构造函数
    func NewPerson(name string, age int8) *Person {
        return &Person{
            name: name,
            age:  age,
        }
    }
    //Dream Person做梦的方法
    func (p Person) Dream() {
        fmt.Printf("%s的梦想是学好Go语言!\n", p.name)
    }
    func main() {
        p1 := NewPerson("测试", 25)
        p1.Dream()
    }

    image.gif

    方法与函数的区别是,函数不属于任何类型,方法属于特定的类型。

    image.gif

    值接收者  VS 指针接收者

    image.gif

      • 值接收者 是go语言特有
      • 值/指针接收者均可接收值/指针

      结构体的“继承”

      Go语言中使用结构体也可以实现其他编程语言中面向对象的继承。

      //Animal 动物
      type Animal struct {
          name string
      }
      func (a *Animal) move() {
          fmt.Printf("%s会动!\n", a.name)
      }
      //Dog 狗
      type Dog struct {
          Feet    int8
          *Animal //通过嵌套匿名结构体实现继承
      }
      func (d *Dog) wang() {
          fmt.Printf("%s会汪汪汪~\n", d.name)
      }
      func main() {
          d1 := &Dog{
              Feet: 4,
              Animal: &Animal{ //注意嵌套的是结构体指针
                  name: "乐乐",
              },
          }
          d1.wang() //乐乐会汪汪汪~
          d1.move() //乐乐会动!
      }

      image.gif

      封装:结构体字段的可见性

      image.gif

      结构体中字段大写开头表示可公开访问小写表示私有(仅在定义当前结构体的包中可访问)。

        • 每个目录一个包
        • main包包含可执行入口
        • 为结构定义的方法必须放在同一个包内
        • 可以是不同文件

        如何库充系统类型或者别人的类型

          • 定义别名
          • 使用组合

          image.gif

          参考链接:

          结构体 · Go语言中文文档


          相关文章
          go语言中遍历映射(map)
          go语言中遍历映射(map)
          304 8
          |
          2月前
          |
          存储 安全 Java
          【Golang】(4)Go里面的指针如何?函数与方法怎么不一样?带你了解Go不同于其他高级语言的语法
          结构体可以存储一组不同类型的数据,是一种符合类型。Go抛弃了类与继承,同时也抛弃了构造方法,刻意弱化了面向对象的功能,Go并非是一个传统OOP的语言,但是Go依旧有着OOP的影子,通过结构体和方法也可以模拟出一个类。
          202 1
          |
          10月前
          |
          编译器 Go
          揭秘 Go 语言中空结构体的强大用法
          Go 语言中的空结构体 `struct{}` 不包含任何字段,不占用内存空间。它在实际编程中有多种典型用法:1) 结合 map 实现集合(set)类型;2) 与 channel 搭配用于信号通知;3) 申请超大容量的 Slice 和 Array 以节省内存;4) 作为接口实现时明确表示不关注值。此外,需要注意的是,空结构体作为字段时可能会因内存对齐原因占用额外空间。建议将空结构体放在外层结构体的第一个字段以优化内存使用。
          |
          5月前
          |
          存储 人工智能 安全
          深入理解 go sync.Map - 基本原理
          本文介绍了 Go 语言中 `map` 在并发使用时的常见问题及其解决方案,重点对比了 `sync.Mutex`、`sync.RWMutex` 和 `sync.Map` 的性能差异及适用场景。文章指出,普通 `map` 不支持并发读写,容易引发错误;而 `sync.Map` 通过原子操作和优化设计,在某些场景下能显著提升性能。同时详细讲解了 `sync.Map` 的基本用法及其适合的应用环境,如读多写少或不同 goroutine 操作不同键的场景。
          232 1
          |
          7月前
          |
          存储 安全 Go
          Map的遍历与判断键是否存在-《Go语言实战指南》
          本文介绍了 Go 语言中对 `map` 的常见操作,包括遍历所有项和判断键是否存在。通过 `for range` 可以遍历 `map` 的键值对、仅键或仅值(需忽略键)。注意,`map` 遍历顺序是随机的。判断键是否存在时,使用双赋值语法 `value, ok := map[key]`,其中 `ok` 表示键是否存在。直接访问不存在的键会返回类型的零值,可能导致逻辑错误。掌握这些机制可更安全高效地处理键值对数据。
          |
          7月前
          |
          JSON Go C语言
          Go语言之定义结构体(Struct)-《Go语言实战指南》
          Go 语言中的结构体(`struct`)是一种复合数据类型,可将多个不同类型的字段组合成一个类型。本文介绍了结构体的基本定义、实例创建方式、字段访问与修改、零值特性、比较规则、嵌套使用及标签功能。通过示例代码详细讲解了如何定义和操作结构体,以及其在 JSON 编码等场景的应用。
          |
          程序员 Go
          go语言中结构体(Struct)
          go语言中结构体(Struct)
          357 71
          |
          10月前
          |
          存储 缓存 安全
          Go 语言中的 Sync.Map 详解:并发安全的 Map 实现
          `sync.Map` 是 Go 语言中用于并发安全操作的 Map 实现,适用于读多写少的场景。它通过两个底层 Map(`read` 和 `dirty`)实现读写分离,提供高效的读性能。主要方法包括 `Store`、`Load`、`Delete` 等。在大量写入时性能可能下降,需谨慎选择使用场景。
          go语言for遍历映射(map)
          go语言for遍历映射(map)
          416 12
          |
          存储 C语言
          C语言如何使用结构体和指针来操作动态分配的内存
          在C语言中,通过定义结构体并使用指向该结构体的指针,可以对动态分配的内存进行操作。首先利用 `malloc` 或 `calloc` 分配内存,然后通过指针访问和修改结构体成员,最后用 `free` 释放内存,实现资源的有效管理。
          1176 13

          热门文章

          最新文章