不做大哥好多年 不做大哥好多年
首页
  • MySQL
  • Redis
  • Elasticsearch
  • Kafka
  • Etcd
  • MongoDB
  • TiDB
  • RabbitMQ
  • 01.GO基础
  • 02.面向对象
  • 03.并发编程
  • 04.常用库
  • 05.数据库操作
  • 06.Beego框架
  • 07.Beego商城
  • 08.GIN框架
  • 09.GIN论坛
  • 10.微服务
  • 01.Python基础
  • 02.Python模块
  • 03.Django
  • 04.Flask
  • 05.SYL
  • 06.Celery
  • 10.微服务
  • 01.Java基础
  • 02.面向对象
  • 03.Java进阶
  • 04.Web基础
  • 05.Spring框架
  • 100.微服务
  • Docker
  • K8S
  • 容器原理
  • Istio
  • 数据结构
  • 算法基础
  • 算法题分类
  • 前置知识
  • PyTorch
  • 01.Python
  • 02.GO
  • 03.Java
  • 04.业务问题
  • 05.关键技术
  • 06.项目常识
  • 10.计算机基础
  • Linux基础
  • Linux高级
  • Nginx
  • KeepAlive
  • ansible
  • zabbix
  • Shell
  • Linux内核

逍遥子

不做大哥好多年
首页
  • MySQL
  • Redis
  • Elasticsearch
  • Kafka
  • Etcd
  • MongoDB
  • TiDB
  • RabbitMQ
  • 01.GO基础
  • 02.面向对象
  • 03.并发编程
  • 04.常用库
  • 05.数据库操作
  • 06.Beego框架
  • 07.Beego商城
  • 08.GIN框架
  • 09.GIN论坛
  • 10.微服务
  • 01.Python基础
  • 02.Python模块
  • 03.Django
  • 04.Flask
  • 05.SYL
  • 06.Celery
  • 10.微服务
  • 01.Java基础
  • 02.面向对象
  • 03.Java进阶
  • 04.Web基础
  • 05.Spring框架
  • 100.微服务
  • Docker
  • K8S
  • 容器原理
  • Istio
  • 数据结构
  • 算法基础
  • 算法题分类
  • 前置知识
  • PyTorch
  • 01.Python
  • 02.GO
  • 03.Java
  • 04.业务问题
  • 05.关键技术
  • 06.项目常识
  • 10.计算机基础
  • Linux基础
  • Linux高级
  • Nginx
  • KeepAlive
  • ansible
  • zabbix
  • Shell
  • Linux内核
  • Python

  • GO

    • 01.GMP模型 ✅
    • 02.Map原理 ✅
    • 03.sync_map ✅
    • 04.sync.Pool
    • 05.垃圾回收 ✅
    • 06.channel
    • 07.内存逃逸
    • 08.内存泄漏
    • 09.mutex锁原理
    • 10.Go常识
      • 01.字符串底层
        • 1、 字符串底层结构
        • 2、reflect.StringHeader
      • 02.数组
      • 03.pointer
      • 04.interface
        • 1、eface空接口
        • 2、iface带方法的接口
      • 05.make和new
      • 06.深浅拷贝
    • 50.Golang常犯错误
    • 51.常见坑1~10
  • Java

  • 业务问题

  • 关键技术

  • 项目常识

  • 计算机基础

  • 常识
  • GO
xiaonaiqiang
2025-02-25
目录

10.Go常识

# Go常识

# 01.字符串底层

# 1、 字符串底层结构

  • Go中,string 是一种只读的字节序列

  • 底层由一个结构体实现的,主要包含以下两个部分

    • 指针:指向存储字符串内容的连续内存块,实际存储的内容是字节序列([]byte)
    • 长度:len 用来表示字符串的长度(字符串不可变,底层字节序列不会被修改)
  • 当容量不够时会重新申请新的内存,Data 指针将指向新的地址,原来的地址空间将被释放

type StringHeader struct {
	Data uintptr      // 字符串首地址,指向底层字节数组的指针
	Len int         	// 字符串长度
}
1
2
3
4
  • 对于字符串Hello,实际底层结构如下

# 2、reflect.StringHeader

  • 字符串和数组类似,内置的 len 函数返回字符串的长度
  • 也可以通过 reflect.StringHeader 结构访问字符串的长度
package main

import (
	"fmt"
	"reflect"
	"unsafe"
)

func main() {
	a :="aaa"
	// 1.unsafe.Pointer(&a)方法可以得到变量a的地址
	fmt.Println(unsafe.Pointer(&a))  // 0xc000054240

	// 2.(*reflect.StringHeader)(unsafe.Pointer(&a)) 可以把字符串a转成底层结构的形式
	b := (*reflect.StringHeader)(unsafe.Pointer(&a)).Len
	fmt.Println(b)  // 3

	// 3.(*[]byte)(unsafe.Pointer(&ssh)) 可以把ssh底层结构体转成byte的切片的指针
	// 4.再通过 *转为指针指向的实际内容
	ssh := *(*reflect.StringHeader)(unsafe.Pointer(&a))
	c := *(*[]byte)(unsafe.Pointer(&ssh))
	fmt.Printf("%v",c)  // [97 97 97]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 02.数组

  • 数组

    • 数组是一个具有固定长度的同类型元素的集合,不能改变

    • 如果需要存储更多的元素,就需要先创建一个更长的数组,再把原来数组里的值复制到新数组里

  • 切片

    • 切片是一个基于数组的动态数据结构,其长度和容量可以动态变化

    • 切片底层内存也是在连续块中分配的

    • 切片本质上是一个结构体,包含了以下三个部分

      • 指针:指向存储数据的数组
      • 长度:元素个数
      • 容量:从切片开始位置到底层数组末尾的元素个数,可以通过 cap() 函数获取

# 03.pointer

  • 指针是一种变量,其值是另一个变量的地址
  • 通过指针,我们可以间接访问或修改该变量
  • 只需要记住以下几点:
    • &变量名: 获取变量的内存地址
    • *pointor:通过指针类型的变量,获取该指针指向的值
package main
import "fmt"

func main() {
	name := "张三"
	p1 := &name        // &变量名: 获取变量的内存地址
	p2 := *&name        // *pointor:通过指针类型的变量,获取该指针指向的值
	fmt.Println(name,p1,p2)
	// 张三 0xc000088230 张三
}
1
2
3
4
5
6
7
8
9
10

  • 指针作用
  • 1)函数参数传递

    • 如果你希望在函数内部修改传入的变量,就需要使用指针传递变量的地址,而不是传递副本
  • 2)优化内存分配

    • 通过指针可以避免不必要的内存拷贝,尤其是在传递大型结构体时
      • 传递指针只会传递地址,而不是整个结构体的副本

# 04.interface

  • golang中的接口分为带方法的接口和空接口
    • iface:表示带方法的接口
    • eface:表示空接口
  • 在 Go 中,interface 可以理解为一组方法的集合

    • 当一个类型实现了某个 interface 的所有方法时
    • 这个类型就实现了这个 interface,并且可以被赋值给该 interface 变量
  • interface{} 是 Go 的空接口,表示任意类型

# 1、eface空接口

  • type: 指向值的具体类型信息(type descriptor)
  • data: 存储具体的值(value)
type emptyInterface struct {
    typ  *type             // 指向值类型的指针
    data unsafe.Pointer    // 存储值的指针
}
1
2
3
4

# 2、iface带方法的接口

  • 对于非空接口(定义了方法的接口),它的内部表示更加复杂,包含三部分
  • itab: 接口表,存储该接口的具体实现信息(包含两个重要的部分)
    • inter: 指向接口类型信息
    • type: 指向具体实现该接口的类型信息
  • data: 存储具体的值
  • methods: 接口的方法集合
type iface struct {
    tab  *itab               // 指向接口表的指针
    data unsafe.Pointer      // 存储值的指针
}
1
2
3
4

# 05.make和new

  • new 和 make 是两个内置函数,主要用来创建并分配类型的内存。

  • make和new区别

    • make 关键字的作用是创建于 slice、map 和 channel 等内置的数据结构
    • new 的作用是为类型申请一片内存空间,并返回指向这片内存的指针
func main() {
	a := make([]int, 3, 10)        // 切片长度为 1,预留空间长度为 10
	a = append(a,1)
	fmt.Printf("%v--%T \n",a,a)    // [0 0 0]--[]int   值----切片本身
	
	var b = new([]int)
	//b = b.append(b,2)           // 返回的是内存指针,所以不能直接 append
	*b = append(*b, 3)            // 必须通过 * 指针取值,才能进行 append 添加
	fmt.Printf("%v--%T",b,b)      // &[]--*[]string  内存的指针---内存指针
}
1
2
3
4
5
6
7
8
9
10

# 06.深浅拷贝

  • 浅拷贝就是只拷贝指针的值,指针指向的内容只有一份
  • 而深拷贝是把指针指向的值拷贝一份
  • slice的浅拷贝就是指slice变量赋值操作
  • slice的深拷贝就是指使用内置的copy函数来拷贝两个slice
package main
import "fmt"

func main() {
	SliceShallowCopy()
	SliceDeepCopy()
}

func SliceShallowCopy() {
	src := []byte {1,2,3,4,5,6}
	dst := src
	fmt.Println("浅拷贝原始数据",src)   // [1 2 3 4 5 6]
	dst[0]=10
	// 修改拷贝数据,原始数据会以前跟着改变
	fmt.Println("after modify[src]:",src)  // [10 2 3 4 5 6]
}

func SliceDeepCopy() {
	src := []byte {1,2,3,4,5,6}
	var dst = make([]byte, len(src))
	copy(dst[:], src)
	fmt.Println("深拷贝前:",src)   // [1 2 3 4 5 6]
	dst[0]=10
	fmt.Println("深拷贝修改拷贝数据值后:",src)   // [1 2 3 4 5 6]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
上次更新: 2025/2/25 11:09:45
09.mutex锁原理
50.Golang常犯错误

← 09.mutex锁原理 50.Golang常犯错误→

最近更新
01
04.数组双指针排序_子数组
03-25
02
08.动态规划
03-25
03
06.回溯算法
03-25
更多文章>
Theme by Vdoing | Copyright © 2019-2025 逍遥子 技术博客 京ICP备2021005373号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式