运维八一 运维八一
首页
运维杂记
编程浅尝
周积跬步
专栏
生活
关于
收藏
  • 分类
  • 标签
  • 归档
Source (opens new window)

运维八一

运维,运维!
首页
运维杂记
编程浅尝
周积跬步
专栏
生活
关于
收藏
  • 分类
  • 标签
  • 归档
Source (opens new window)
  • Go

    • 前言

    • Go基础知识

    • Go基本语法

    • 实战项目:简单web服务

    • 基本数据类型

    • 内置运算符

    • 分支和循环

    • 函数 function

    • 结构体 struct

    • 方法 method

    • 实战项目:跟踪函数调用链

    • 接口 interface

    • 并发 concurrency

    • 指针

      • 指针类型
        • 1. 指针类型
          • 1.1 指针类型的定义
          • 1.2 指针类型变量的内存单元
      • 二级指针
      • 指针用途与使用限制
    • 实战项目:实现轻量级线程池

    • 实战项目:实现TCP服务器

    • go常用包

    • Gin框架

    • go随记

  • Python

  • Shell

  • Java

  • Vue

  • 前端

  • 编程浅尝
  • Go
  • 指针
lyndon
2022-06-07
目录

指针类型

# 1. 指针类型

# 1.1 指针类型的定义

如果拥有一个类型 T,那么以 T 作为基类型的指针类型为 *T。

指针类型是依托某一个类型而存在的,比如:一个整型为 int,那么它对应的整型指针就是 *int,也就是在 int 的前面加上一个星号。没有 int 类型,就不会有 *int 类型。而 int 也被称为 *int 指针类型的基类型。

声明一个指针类型变量的语法与非指针类型的普通变量是一样的,以声明一个 *T 指针类型的变量为例:

var p *T
1

不过 Go 中也有一种指针类型是例外,它不需要基类型,它就是 unsafe.Pointer。unsafe.Pointer 类似于 C 语言中的 void*,用于表示一个通用指针类型,也就是任何指针类型都可以显式转换为一个 unsafe.Pointer,而 unsafe.Pointer 也可以显式转换为任意指针类型,如下面代码所示:

var p *T
var p1 = unsafe.Pointer(p) // 任意指针类型显式转换为unsafe.Pointer
p = (*T)(p1)               // unsafe.Pointer也可以显式转换为任意指针类型
1
2
3

unsafe.Pointer 是 Go 语言的高级特性,在 Go 运行时与 Go 标准库中 unsafe.Pointer 都有着广泛的应用。

如果指针类型变量没有被显式赋予初值,那么它的值为 nil:

var p *T
println(p == nil) // true
1
2

给一个指针类型变量赋值:

var a int = 13
var p *int = &a  // 给整型指针变量p赋初值
1
2

用&a作为 *int 指针类型变量 p 的初值,这里变量 a 前面的&符号称为取地址符号,这一行的含义就是将变量 a 的地址赋值给指针变量 p。

# 1.2 指针类型变量的内存单元

非指针类型变量的内存单元,以最简单的整型变量为例:

img

对于非指针类型变量,Go 在对应的内存单元中放置的就是该变量的值。对这些变量进行修改操作的结果,也会直接体现在这个内存单元上,如下图所示:

img

指针类型变量的内存单元,以 *int 类型指针变量为例:

img

Go 为指针变量 p 分配的内存单元中存储的是整型变量 a 对应的内存单元的地址。也正是由于指针类型变量存储的是内存单元的地址,指针类型变量的大小与其基类型大小无关,而是和系统地址的表示长度有关。

package main

import "unsafe"

type foo struct {
    id   string
    age  int8
    addr string
}

func main() {
    var p1 *int
    var p2 *bool
    var p3 *byte
    var p4 *[20]int
    var p5 *foo
    var p6 unsafe.Pointer
    println(unsafe.Sizeof(p1)) // 8 
    println(unsafe.Sizeof(p2)) // 8
    println(unsafe.Sizeof(p3)) // 8
    println(unsafe.Sizeof(p4)) // 8
    println(unsafe.Sizeof(p5)) // 8
    println(unsafe.Sizeof(p6)) // 8
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

通过 unsafe.Sizeof 函数来计算每一个指针类型的大小,无论指针的基类型是什么,不同类型的指针类型的大小在同一个平台上是一致的。在 x86-64 平台上,地址的长度都是 8 个字节。

unsafe 包的 Sizeof 函数原型如下:

func Sizeof(x ArbitraryType) uintptr
1

这个函数的返回值类型是 uintptr,这是一个 Go 预定义的标识符。通过 go doc 可以查到这一类型代表的含义:uintptr 是一个整数类型,它的大小足以容纳任何指针的比特模式(bit pattern)。可以将这句话理解为:在 Go 语言中 uintptr 类型的大小就代表了指针类型的大小。

一旦指针变量得到了正确赋值,也就是指针指向某一个合法类型的变量,就可以通过指针读取或修改其指向的内存单元所代表的基类型变量,比如:

var a int = 17
var p *int = &a
println(*p) // 17 
(*p) += 3
println(a)  // 20
1
2
3
4
5

如下图:

img

通过指针变量读取或修改其指向的内存地址上的变量值,这个操作被称为指针的解引用(dereference)。它的形式就是在指针类型变量的前面加上一个星号。

上次更新: 2022/06/12, 15:48:09
原子操作 atomic包
二级指针

← 原子操作 atomic包 二级指针→

最近更新
01
ctr和crictl显示镜像不一致
03-13
02
alpine镜像集成常用数据库客户端
03-13
03
create-cluster
02-26
更多文章>
Theme by Vdoing | Copyright © 2015-2024 op81.com
苏ICP备18041258号-2
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式