「Go笔记-02」变量、基本数据类型、数据类型间转换、进制转换,看这一篇就Go了

前言

一个程序就是一个世界,不论是使用哪种高级程序语言编写程序, 变量都是其程序的基本组成单位,

变量

在 go 中 变量是用于存储数据的命名空间(内存位置),它可以表示一个值,这个值在程序执行过程中可能会发生改变。

+-------------+       +---------------------+
| 变量名: myVar|------>| 内存地址: 0x12345678|
+-------------+       +---------------------+
                      | 数据值:    42        |
                      +---------------------+

关键概念

  1. 标识符(名称): 变量具有一个唯一的名称,用于在程序中引用它。变量名应遵循编程语言的命名规则,通常以字母、数字和下划线组成,并且不能以数字开头。关键字和预定义标识符可以查看附录 :附录

  2. 数据类型: 变量有一个与之关联的数据类型,如整数、浮点数、布尔值或自定义类型。数据类型决定了变量可以存储的值的范围和类型。

  3. 值: 变量表示一个值,这个值可以在程序执行过程中改变。通过赋值操作,我们可以将一个新值存储到变量中。

  4. 作用域: 变量在程序中的可见范围称为作用域。作用域决定了在哪些部分的代码中可以访问和修改变量。通常,局部变量在函数或代码块内部定义,全局变量在整个程序范围内定义。

  5. 生命周期: 变量的生命周期是从创建到销毁的过程。局部变量的生命周期通常与函数或代码块的执行周期相同;全局变量的生命周期从程序启动到程序结束。

变量的使用

  • go 中 局部变量的声明方式有 4种
  • go 中 全局变量的声明方式有 2 种

示例

package main

import "fmt"

// 全局变量
var globalInt = 100
var globalFloat = 9.7

// 一次性声明多个全局变量
var (
	globalInt2    = 500
	globalString2 = "netty"
)

func main() {
	// 局部变量
		// 1. 变量声明
	var age int
	// 2. 变量赋值
	age = 18
	// 3. 变量使用
	fmt.Println("age =", age)

	//  2、声明和赋值可以合并成一句
	var age2 int = 19
	fmt.Println("age2 =", age2)

	// 以下代码将会报错,因为变量 age 重复声明
	// var age int = 20
	// fmt.Println("age =", age)

	// 以下代码将会报错,因为浮点数不能直接赋值给整数类型变量
	// var num int = 12.56
	// fmt.Println("num =", num)

	// 指定变量类型,使用默认值
	var age3 int
	fmt.Println(age2)

	//  3、自动类型推断
	var name = "tom"
	fmt.Println(name)

	//4、 省略 var 关键字,使用 :=
	gender := "男"
	fmt.Println(gender)

	// 一次性声明多个局部变量
	var n1, n2, n3 int
	fmt.Println(n1)
	fmt.Println(n2)
	fmt.Println(n3)

	// 一次性声明多个局部变量并赋值
	var n4, name2, n5 = 10, "jack", 7.8
	fmt.Println(n4)
	fmt.Println(name2)
	fmt.Println(n5)

	// 使用 := 一次性声明多个局部变量并赋值
	n6, height := 6.9, 100.6
	fmt.Println(n6)
	fmt.Println(height)

	// 输出全局变量
	fmt.Println(globalInt)
	fmt.Println(globalFloat)
	fmt.Println(globalInt2)
	fmt.Println(globalString2)
}

数据类型

Golang变量的数据类型包含基本数据类型和派生(复杂)数据类型

类别 数据类型 说明
基本数据类型 bool 布尔类型,值为 true 或 false
int8, int16, int32, int64 有符号整数类型,分别占用 8, 16, 32, 64 位存储空间
uint8, uint16, uint32, uint64 无符号整数类型,分别占用 8, 16, 32, 64 位存储空间
int 有符号整数类型,大小与操作系统位数相关(32 位或 64 位)
uint 无符号整数类型,大小与操作系统位数相关(32 位或 64 位)
uintptr 无符号整数类型,足以存储指针的大小
float32, float64 浮点数类型,分别占用 32 位和 64 位存储空间
complex64, complex128 复数类型,分别占用 64 位和 128 位存储空间
byte 字节类型,等同于 uint8
rune Unicode 字符类型,等同于 int32
string 字符串类型
派生数据类型 array 固定长度的数组类型
slice 可变长度的数组类型(切片)
map 无序键值对集合(字典)
struct 自定义数据结构(结构体)
interface 定义一组方法的集合(接口)
pointer 存储变量内存地址的类型(指针)
channel 用于协程间通信的类型(通道)
function 函数类型

整数类型

简单的说,就是用于存放整数值的,比如10,-45,6712等等。

有符号整数类型:

类型 是否有符号 占用空间 取值范围
int8 8 位 (1 字节) -128 到 127 (-2^7 到 2^7-1)
int16 16 位 (2 字节) -32,768 到 32,767 (-2^15 到 2^15-1)
int32 32 位 (4 字节) -2,147,483,648 到 2,147,483,647 (-2^31 到 2^31-1)
int64 64 位 (8 字节) -9,223,372,036,854,775,808 到 9,223,372,036,854,775,807 (-2^63 到 2^63-1)
PS:127怎么算出来的?
01111111 –>二进制 —》转为十进制:
1*2^6   +   1*2^5  +  1*2^4  +   1*2^3  +   1*2^2  +   1*2^1  +    1*2^0
= 64      +   32         +    16          +   8        +      4       +    2     +   1
= 127
PS:-128怎么算出来的?
10000000 —>二进制 —>一看就是个负数
10000000 –》负数的二进制
减1:01111111
取反:10000000     —》得到一个正数    2^7 = 128
加负号:-128

无符号整数类型:

这些类型可用于表示不同范围的非负整数值。

类型 是否有符号 占用空间 取值范围
uint8 8 位 (1 字节) 0 到 255 (0 到 2^8-1)
uint16 16 位 (2 字节) 0 到 65,535 (0 到 2^16-1)
uint32 32 位 (4 字节) 0 到 4,294,967,295 (0 到 2^32-1)
uint64 64 位 (8 字节) 0 到 18,446,744,073,709,551,615 (0 到 2^64-1)

表数范围的边界计算:

11111111= 2^7+127 = 128 + 127 = 255

00000000 = 0

其他整数类型

以下是一个完整的表格,将取值范围放在同一个单元格中:

类型 是否有符号 占用空间 取值范围 说明
int 32 位或64 位 (依赖操作系统) 32 位: -2^31 到 2^31-1
64 位: -2^63 到 2^63-1
有符号整数,大小与操作系统位数相关
uint 32 位或64 位 (依赖操作系统) 32 位: 0 到 2^32-1
64 位: 0 到 2^64-1
无符号整数,大小与操作系统位数相关
uintptr 32 位或64 位 (依赖操作系统) 32 位: 0 到 2^32-1
64 位: 0 到 2^64-1
无符号整数,足以存储指针的大小
byte 8 位 (1 字节) 0 到 2^8-1 字节类型,等同于 uint8
rune 32 位 (4 字节) -2^31 到 2^31-1 Unicode 字符类型,等同于 int32

这些类型在特定场景下(如操作系统相关编程、处理字节和 Unicode 字符)非常有用。

PS:Golang的整数类型,默认声明为int类型

查询变量占用的字节数

在 Go 语言中,可以使用 unsafe.Sizeof() 函数来查看变量占用的字节数。unsafe.Sizeof() 函数返回一个变量所占用的字节数,以 uintptr 类型表示。请注意,使用 unsafe 包可能会带来潜在的安全风险和跨平台兼容性问题,因此在使用时要谨慎。

package main

import (
	"fmt"
	"unsafe"
)

func main() {
	var a int32 = 10
	var b float64 = 20.5
	var c bool = true
	var d byte = 255
	var e rune = 'A'
	var f string = "hello"

	fmt.Printf("Size of int32: %d bytes\\n", unsafe.Sizeof(a))
	fmt.Printf("Size of float64: %d bytes\\n", unsafe.Sizeof(b))
	fmt.Printf("Size of bool: %d bytes\\n", unsafe.Sizeof(c))
	fmt.Printf("Size of byte: %d bytes\\n", unsafe.Sizeof(d))
	fmt.Printf("Size of rune: %d bytes\\n", unsafe.Sizeof(e))
	fmt.Printf("Size of string: %d bytes\\n", unsafe.Sizeof(f))
}

在这个示例中,我们使用 unsafe.Sizeof() 函数查看了不同类型变量占用的字节数,并将结果打印到控制台。请注意,对于 string 类型,unsafe.Sizeof() 函数返回的值是字符串头部的大小,而不是实际字符串内容的大小。要获取字符串内容的长度,可以使用 len() 函数。

这么多整数类型,使用的时候该如何选择呢?

Golang程序中整型变量在使用时,遵守保小不保大的原则,

即:在保证程序正确运行下,尽量使用占用空间小的数据类型

浮点类型

浮点类型介绍:

简单的说,就是用于存放小数值的,比如3.14、0.28、-7.19等等。

浮点类型种类:

类型 是否有符号 占用空间 取值范围及精度 说明
float32 32 位 (4 字节) 1.18e-38 到 3.4e38(约 7 位有效数字) 单精度浮点数
float64 64 位 (8 字节) 2.23e-308 到 1.8e308(约 16 位有效数字) 双精度浮点数(通常使用)

在大多数情况下,推荐使用 float64 类型,因为它具有更高的精度和更广泛的取值范围。

PS:底层存储空间和操作系统无关

PS:浮点类型底层存储:符号位+指数位+尾数位,所以尾数位只是存了 一个大概,很可能会出现精度的损失。

示例:

package main

import "fmt"

func main() {
	// 定义正的 float32 类型变量
	var num1 float32 = 3.14
	fmt.Println(num1)

	// 定义负的 float32 类型变量
	var num2 float32 = -3.14
	fmt.Println(num2)

	// 使用科学计数法表示的 float32 类型变量
	var num3 float32 = 314e-2
	fmt.Println(num3)

	// 使用科学计数法表示的 float32 类型变量
	var num4 float32 = 314e+2
	fmt.Println(num4)

	// 使用科学计数法表示的 float32 类型变量
	var num5 float32 = 314e+2
	fmt.Println(num5)

	// 使用科学计数法表示的 float64 类型变量
	var num6 float64 = 314e+2
	fmt.Println(num6)

	// float32 类型变量可能存在精度损失
	var num7 float32 = 256.000000916
	fmt.Println(num7)

	// float64 类型变量具有更高的精度
	var num8 float64 = 256.000000916
	fmt.Println(num8)

	// Go 语言中默认的浮点类型为 float64
	var num9 = 3.17
	fmt.Printf("num9对应的默认的类型为:%T", num9)
}

字符类型

示例:

package main

import "fmt"

func main() {
	// 定义 ASCII 字符类型的数据 (byte 类型)
	var char1 byte = 'a'
	fmt.Println(char1) // 输出: 97

	var char2 byte = '6'
	fmt.Println(char2) // 输出: 54

	var char3 byte = '('
	fmt.Println(char3 + 20) // 输出: 40

	// 字符类型本质上是一个整数,可以直接参与运算。输出时,会将对应的码值输出。
	// 字母、数字、标点等字符在底层按照 ASCII 进行存储。

	// 定义 Unicode 字符类型的数据 (int 类型)
	var char4 int = '中'
	fmt.Println(char4) // 输出: 20013

	// 汉字字符在底层对应的是 Unicode 码值。
	// 码值为 20013,超出 byte 类型能存储的范围,因此使用 int 类型存储。
	// 总结:Go 语言的字符使用 UTF-8 编码(Unicode 是对应的字符集,UTF-8 是 Unicode 的其中一种编码方案)。

	var char5 byte = 'A'
	// 若要显示对应的字符,必须采用格式化输出
	fmt.Printf("char5 对应的具体的字符为:%c", char5) // 输出: A
}

转义字符

转义字符 定义 作用
\\ 反斜杠 表示一个反斜杠字符
\' 单引号 表示一个单引号字符
\" 双引号 表示一个双引号字符
\n 换行符 在输出中插入一个换行符
\r 回车符 在输出中插入一个回车符,使光标移动到行首
\t 制表符(水平制表符) 在输出中插入一个制表符,用于对齐文本
\b 退格符 在输出中插入一个退格符,使光标回退一个字符位置
\f 换页符 在输出中插入一个换页符,使光标移动到下一页
\v 垂直制表符 在输出中插入一个垂直制表符,用于垂直对齐文本
\ooo 八进制编码字符 表示一个八进制编码的字符
\xhh 十六进制编码字符 表示一个十六进制编码的字符
\uhhhh Unicode 编码字符 表示一个 Unicode 编码的字符(16 位)
\Uhhhhhhhh Unicode 编码字符 表示一个 Unicode 编码的字符(32 位)

示例

package main

import "fmt"

func main() {
	// 演示转义字符的用法

	// \n 换行
	fmt.Println("aaa\nbbb")

	// \b 退格
	fmt.Println("aaa\bbbb")

	// \r 回车:光标回到本行的开头,后续输入会替换原有的字符
	fmt.Println("aaaaa\rbbb")

	// \t 制表符:水平制表符,用于对齐文本
	fmt.Println("aaaaaaaaaaaaa")
	fmt.Println("aaaaa\tbbbbb")
	fmt.Println("aaaaaaaa\tbbbbb")

	// \" 双引号:表示一个双引号字符
	fmt.Println("\"Golang\"")
}

布尔类型

  • 布尔类型也叫bool类型,bool类型数据只允许取值true和false
  • 布尔类型占1个字节。
  • 布尔类型适于逻辑运算,一般用于程序流程控制
package main

import "fmt"

func main() {
	// 测试布尔类型的数值
	var flag1 bool = true
	fmt.Println(flag1) // 输出: true

	var flag2 bool = false
	fmt.Println(flag2) // 输出: false

	var flag3 bool = 5 < 9
	fmt.Println(flag3) // 输出: true
}

字符串类型

字符串就是一串固定长度的字符连接起来的字符序列。

字符串示例

package main

import "fmt"

func main() {
	// 1. 定义一个字符串
	var s1 string = "全面拥抱Golang"
	fmt.Println(s1)

	// 2. 字符串是不可变的:指的是字符串一旦定义好,其中的字符的值不能改变
	var s2 string = "abc"
	// s2 = "def"
	// s2[0] = 't'
	fmt.Println(s2)

	// 3. 字符串的表示形式
	// (1) 如果字符串中没有特殊字符,字符串的表示形式用双引号
	// var s3 string = "asdfasdfasdf"

	// (2) 如果字符串中有特殊字符,字符串的表示形式用反引号 ``
	var s4 string = `
package main
import "fmt"

func main(){
	//测试布尔类型的数值:
	var flag01 bool = true
	fmt.Println(flag01)

	var flag02 bool = false
	fmt.Println(flag02)

	var flag03 bool = 5 < 9
	fmt.Println(flag03)
}`
	fmt.Println(s4)

	// 4. 字符串的拼接效果
	var s5 string = "abc" + "def"
	s5 += "hijk"
	fmt.Println(s5)

	// 当一个字符串过长的时候:注意:+ 保留在上一行的最后
	var s6 string = "abc" + "def" + "abc" + "def" + "abc" + "def" +
		"abc" + "def" + "abc" + "def" + "abc" + "def" + "abc" + "def" +
		"abc" + "def" + "abc" + "def" + "abc" + "def" + "abc" + "def" +
		"abc" + "def" + "abc" + "def" + "abc" + "def" + "abc" + "def"
	fmt.Println(s6)
}

基本数据类型的默认值

在Golang中数据类型都有一个默认值,当程序员没有赋值时,就会保留默认值(默认值又叫零值)。

以下是一个表格,展示了 Go 语言中各种数据类型的默认值:

数据类型 默认值 说明
int 0 整数类型默认值
uint 0 无符号整数类型默认值
float32 0.0 单精度浮点数默认值
float64 0.0 双精度浮点数默认值
bool false 布尔类型默认值
string "" 空字符串默认值
array 元素的默认值 数组元素类型的默认值
slice nil 切片类型默认值
map nil 映射类型默认值
pointer nil 指针类型默认值
function nil 函数类型默认值
channel nil 通道类型默认值
struct 结构体字段的默认值 结构体中各字段类型的默认值

这个表格包含了 Go 语言中各种数据类型的默认值。当声明一个变量而不指定初始值时,变量会被赋予其数据类型的默认值。例如,整数类型的默认值是 0,布尔类型的默认值是 false,字符串类型的默认值是空字符串("")。对于复合数据类型(如数组、切片、映射、结构体等),它们的默认值取决于其元素或字段的数据类型。

基本数据类型之间的转换

Go在不同类型的变量之间赋值时需要显式转换,并且只有显式转换(强制转换)。

语法:

表达式T(v)将值v转换为类型T

  • T : 就是数据类型
  • v : 就是需要转换的变量

类型转换示例

package main

import "fmt"

func main() {
	// 类型转换示例

	// 声明一个 int 类型变量
	var num1 int = 100
	fmt.Println(num1)

	// 将 int 类型转换为 float32 类型
	var num2 float32 = float32(num1)
	fmt.Println(num2)

	// 注意:num1 的类型仍然是 int,只是将 num1 的值 100 转换为了 float32 类型
	fmt.Printf("%T\n", num1) // 输出: int

	// 将 int64 类型转换为 int8 类型时,可能会发生数据溢出
	var num3 int64 = 888888
	var num4 int8 = int8(num3)
	fmt.Println(num4) // 输出: 56

	// 将 int32 类型转换为 int64 类型,并进行数值运算
	var num5 int32 = 12
	var num6 int64 = int64(num5) + 30
	fmt.Println(num5)
	fmt.Println(num6)

	// 将 int64 类型转换为 int8 类型时,可能会发生数据溢出
	var num7 int64 = 12
	var num8 int8 = int8(num7) + 127
	// 编译通过,但结果可能会溢出
	fmt.Println(num8) // 输出: -117

	// 将 int64 类型转换为 int8 类型时,可能会发生数据溢出
	// var num9 int8 = int8(num7) + 128 // 编译不会通过,因为 128 超出了 int8 的取值范围
}

基本数据类型转为string

在程序开发中,我们经常需要将基本数据类型转成string类型。或者将string类型转成基本数据类型。

方式1:mt.Sprintf(“%参数”,表达式)    推荐方式

package main

import (
	"fmt"
)

func main() {
	// 将 int 类型转换为 string 类型
	num1 := 42
	str1 := fmt.Sprintf("%d", num1)
	fmt.Printf("str1: %s, type: %T\n", str1, str1)

	// 将 float64 类型转换为 string 类型
	num2 := 3.14159
	str2 := fmt.Sprintf("%.2f", num2)
	fmt.Printf("str2: %s, type: %T\n", str2, str2)

	// 将 bool 类型转换为 string 类型
	flag := true
	str3 := fmt.Sprintf("%t", flag)
	fmt.Printf("str3: %s, type: %T\n", str3, str3)
}
按使用频率排序的 fmt.Printf() 占位符:
占位符 说明 示例
%v 默认格式输出,根据变量的类型自动选择输出格式 fmt.Printf("%v", x)
%s 输出字符串 fmt.Printf("%s", x)
%d 输出十进制整数 fmt.Printf("%d", x)
%f 输出浮点数,不使用科学计数法 fmt.Printf("%f", x)
%T 输出变量的类型 fmt.Printf("%T", x)
%t 输出布尔值 fmt.Printf("%t", x)
%x 输出十六进制整数,使用小写字母 fmt.Printf("%x", x)
%X 输出十六进制整数,使用大写字母 fmt.Printf("%X", x)
%b 输出整数的二进制表示 fmt.Printf("%b", x)
%e 输出科学计数法表示的浮点数,使用小写字母 e fmt.Printf("%e", x)
%E 输出科学计数法表示的浮点数,使用大写字母 E fmt.Printf("%E", x)
%g 输出浮点数,根据数值大小自动选择使用 %f 或 %e 格式 fmt.Printf("%g", x)
%G 输出浮点数,根据数值大小自动选择使用 %f 或 %E 格式 fmt.Printf("%G", x)
%p 输出指针的十六进制表示 fmt.Printf("%p", x)
%c 输出整数对应的 Unicode 字符 fmt.Printf("%c", x)
%o 输出八进制整数 fmt.Printf("%o", x)
%q 输出带引号的字符串或字符,对于字符串,输出双引号;对于字符,输出单引号 fmt.Printf("%q", x)
%U 输出 Unicode 码点表示的字符串 fmt.Printf("%U", x)
%+v 输出结构体时,包含字段名 fmt.Printf("%+v", x)
%#v 输出 Go 语言语法格式的值 fmt.Printf("%#v", x)
%% 输出一个百分号(% fmt.Printf("%%")
%n 输出已写入的字节数(n 为 int 类型的指针) fmt.Printf("%n", &x)

方式2:使用strconv包的函数

package main

import (
	"fmt"
	"strconv"
)

func main() {
	// 将 int 类型转换为 string 类型
	num1 := 42
	str1 := strconv.Itoa(num1)
	fmt.Printf("str1: %s, type: %T\n", str1, str1)

	// 将 float64 类型转换为 string 类型
	num2 := 3.14159
	str2 := strconv.FormatFloat(num2, 'f', 2, 64)
	fmt.Printf("str2: %s, type: %T\n", str2, str2)

	// 将 bool 类型转换为 string 类型
	flag := true
	str3 := strconv.FormatBool(flag)
	fmt.Printf("str3: %s, type: %T\n", str3, str3)

	// 将 int64 类型转换为 string 类型
	num3 := int64(123456789)
	str4 := strconv.FormatInt(num3, 10)
	fmt.Printf("str4: %s, type: %T\n", str4, str4)

	// 将 uint64 类型转换为 string 类型
	num4 := uint64(987654321)
	str5 := strconv.FormatUint(num4, 10)
	fmt.Printf("str5: %s, type: %T\n", str5, str5)
}

两者差异

fmt.Sprintf()strconv 包中的函数之间的主要区别在于性能和灵活性:

  1. 性能: strconv 包中的函数通常比 fmt.Sprintf() 更快,因为它们专门针对特定的数据类型进行了优化。fmt.Sprintf() 是一个通用的格式化字符串函数,因此它需要处理更多的类型和格式选项,这可能会导致性能略低于 strconv 包中的函数。
  2. 灵活性: fmt.Sprintf() 提供了更多的格式选项和控制,可以轻松地处理多种数据类型和格式。而 strconv 包中的函数是专门针对特定数据类型的,因此在某些情况下可能不如 fmt.Sprintf() 灵活。

根据实际需求和性能要求,可以选择使用 fmt.Sprintf()strconv 包中的函数进行数据类型转换。在对性能要求不高的情况下,使用 fmt.Sprintf() 可能更方便和简单。在对性能要求较高的情况下,可以考虑使用 strconv 包中的函数。

string转为基本数据类型

package main

import (
	"fmt"
	"strconv"
)

func main() {
	// 将 string 类型转换为 int 类型
	str1 := "42"
	num1, err1 := strconv.Atoi(str1)
	if err1 != nil {
		fmt.Println("Error:", err1)
	} else {
		fmt.Printf("num1: %d, type: %T\n", num1, num1)
	}

	// 将 string 类型转换为 float64 类型
	str2 := "3.14159"
	num2, err2 := strconv.ParseFloat(str2, 64)
	if err2 != nil {
		fmt.Println("Error:", err2)
	} else {
		fmt.Printf("num2: %f, type: %T\n", num2, num2)
	}

	// 将 string 类型转换为 bool 类型
	str3 := "true"
	flag, err3 := strconv.ParseBool(str3)
	if err3 != nil {
		fmt.Println("Error:", err3)
	} else {
		fmt.Printf("flag: %t, type: %T\n", flag, flag)
	}

	// 将 string 类型转换为 int64 类型
	str4 := "123456789"
	num3, err4 := strconv.ParseInt(str4, 10, 64)
	if err4 != nil {
		fmt.Println("Error:", err4)
	} else {
		fmt.Printf("num3: %d, type: %T\n", num3, num3)
	}

	// 将 string 类型转换为 uint64 类型
	str5 := "987654321"
	num4, err5 := strconv.ParseUint(str5, 10, 64)
	if err5 != nil {
		fmt.Println("Error:", err5)
	} else {
		fmt.Printf("num4: %d, type: %T\n", num4, num4)
	}
}

指针

  • &取内存地址
  • *根据地址取值
package main

import "fmt"

func main() {
	// 声明一个整数变量 num
	num := 42
	fmt.Println("num:", num)

	// 声明一个指针变量 ptr
	var ptr *int

	// 将 num 的地址赋值给 ptr
	ptr = &num
	fmt.Println("ptr points to:", *ptr)

	// 通过 ptr 访问 num 的值
	fmt.Println("Value of num through ptr:", *ptr)

	// 通过 ptr 修改 num 的值
	*ptr = 100
	fmt.Println("New value of num:", num)
}
sequenceDiagram participant main participant num participant ptr main->>num: 声明整数变量 num Note over main,num: int num = 42 main->>ptr: 声明指针变量 ptr Note over main,ptr: int *ptr main->>ptr: 将 num 的地址赋值给 ptr Note over main,ptr: ptr = &num main->>ptr: 通过 ptr 访问 num 的值 Note over main,ptr: *ptr main->>ptr: 通过 ptr 修改 num 的值 Note over main,ptr: *ptr = 100

指针细节

  • 指针变量的地址不可以不匹配:不能指向不同数据类型
  • 基本数据类型(又叫值类型),都有对应的指针类型,形式为*数据类型,比如int的对应的指针就是*int, float32对应的指针类型就是*float32。依次类推。

附录

关键字和预定义标识符

关键字是 Go 语言中具有特殊含义的单词,用于控制语言结构。预定义标识符是 Go 语言中预先声明的常量、类型、函数等。在命名变量、函数或类型时,应避免使用这些关键字和预定义标识符。

关键字就是程序发明者规定的有特殊含义的单词,又叫保留字。

关键字

go语言中一共有25个关键字。

关键字 说明
break 跳出循环或 switch 语句
default switch 语句的默认分支
func 声明函数或方法
interface 声明接口类型
select 用于从多个通道中接收数据
case switch 语句的每个分支
defer 延迟执行函数,直到包含该 defer 语句的函数执行完毕
go 以并发方式运行函数
map 声明映射类型
struct 声明结构体类型
chan 声明通道类型
else if 语句的其他分支
goto 无条件跳转到指定标签位置
package 声明包名
switch 多分支选择语句
const 声明常量
fallthrough 使 switch 语句继续执行下一个 case 分支,而不是跳出 switch 语句
if 条件判断语句
range 用于遍历数组、切片、字符串或映射的元素
type 声明自定义类型
continue 跳过当前循环的剩余部分,进入下一次循环
for 循环语句
import 导入外部包
return 从函数返回
var 声明变量

Go 语言的 36 个预定义标识符

基本数据类型
预定义标识符 说明
bool 布尔类型
byte 字节类型,等同于 uint8
complex64 64 位复数类型
complex128 128 位复数类型
error 错误接口
float32 单精度浮点数类型
float64 双精度浮点数类型
int 有符号整数类型
int8 8 位有符号整数类型
int16 16 位有符号整数类型
int32 32 位有符号整数类型
int64 64 位有符号整数类型
rune 字符类型,等同于 int32
string 字符串类型
uint 无符号整数类型
uint8 8 位无符号整数类型
uint16 16 位无符号整数类型
uint32 32 位无符号整数类型
uint64 64 位无符号整数类型
uintptr 无符号整数指针类型
系统内置函数
预定义标识符 说明
make 分配内存并初始化切片、映射或通道
new 分配内存并初始化变量
panic 引发运行时恐慌
recover 从运行时恐慌中恢复
print 打印参数列表
println 打印参数列表并换行
预定义常量
预定义标识符 说明
true 布尔类型的真值
false 布尔类型的假值
iota 用于常量计数器的特殊常量
nil 零值指针

这些表格包含了 Go 语言的预定义标识符,包括基本数据类型、系统内置函数和预定义常量。在命名变量、函数或类型时,应避免使用这些预定义标识符。

扩展:进制和进制转换

在 Go 语言中,可以使用不同的进制表示整数,如二进制、八进制、十进制和十六进制。以下是各种进制表示的整数的示例:

  • 二进制:以 0b0B 开头,后跟二进制数字(01)。例如:0b10100B1010 表示十进制数 10。
  • 八进制:以 0 开头,后跟八进制数字(07)。例如:012 表示十进制数 10。
  • 十进制:直接写十进制数字(09)。例如:10 表示十进制数 10。
  • 十六进制:以 0x0X 开头,后跟十六进制数字(09AFaf)。例如:0xA0Xa 表示十进制数 10。

进制转换

在 Go 语言中,可以使用 fmt.Printf()strconv 包中的函数进行进制转换。以下是一些示例:

package main

import (
	"fmt"
	"strconv"
)

func main() {
	num := 42

	// 十进制转二进制
	binStr := strconv.FormatInt(int64(num), 2)
	fmt.Printf("Decimal %d to binary: %s\n", num, binStr)

	// 十进制转八进制
	octStr := strconv.FormatInt(int64(num), 8)
	fmt.Printf("Decimal %d to octal: %s\n", num, octStr)

	// 十进制转十六进制
	hexStr := strconv.FormatInt(int64(num), 16)
	fmt.Printf("Decimal %d to hexadecimal: %s\n", num, hexStr)

	// 二进制转十进制
	binNum, _ := strconv.ParseInt("101010", 2, 0)
	fmt.Printf("Binary 101010 to decimal: %d\n", binNum)

	// 八进制转十进制
	octNum, _ := strconv.ParseInt("52", 8, 0)
	fmt.Printf("Octal 52 to decimal: %d\n", octNum)

	// 十六进制转十进制
	hexNum, _ := strconv.ParseInt("2A", 16, 0)
	fmt.Printf("Hexadecimal 2A to decimal: %d\n", hexNum)
}

在这个示例中,我们使用了 strconv.FormatInt()strconv.ParseInt() 函数进行进制转换。这些函数可以根据需要将整数在不同进制之间进行转换。注意,strconv.ParseInt() 函数在转换过程中可能会发生错误(例如,无效的输入或溢出),因此需要检查返回的错误。

感谢阅读,如果觉得对你有帮助,就在右下角点个赞吧,感谢!

合抱之木,生于毫末;九层之台,起于累土;千里之行,始于足下。