您现在的位置是:首页 >学无止境 >Golang 数据类型网站首页学无止境
Golang 数据类型
数据类型
在 golang 中,数据类型是用于定义变量可以存储的数据种类和范围的。由于 golang 是一种静态类型语言,这意味着在编译时必须明确指定变量的类型。golang 提供了丰富的内置数据类型,可以分为两大类:基本数据类型和复合数据类型。
基本数据类型
基本数据类型划分为:数值类型、布尔类型、字符串类型。
数值类型
数值类型划分为:整数类型、浮点数类型、复数类型。
整数类型
整数类型划分为:有符号整数、无符号整数。
有符号整数
| 数据类型 | 位数 | 范围 | 说明 |
|---|---|---|---|
int8 | 8 | -128 到 127 | 8 位有符号整数,占用 1 个字节 |
int16 | 16 | -32768 到 32767 | 16 位有符号整数,占用 2 个字节 |
int32 | 32 | -2147483648 到 2147483647 | 32 位有符号整数,占用 4 个字节 |
int64 | 64 | -9223372036854775808 到 9223372036854775807 | 64 位有符号整数,占用 8 个字节 |
int | 平台相关 | 32 位系统:-2147483648 到 2147483647;64 位系统:-2147483648 到 2147483647 | 默认整数类型,大小取决于平台(通常是 4 个字节) |
package main
import "fmt"
func main() {
// 声明并初始化有符号整数
var a int8 = -128
var b int16 = 32767
var c int32 = -2147483648
var d int64 = 9223372036854775807
var e int = -100 // 默认的 int 类型
// 打印有符号整数
fmt.Println("int8:", a) // int8: -128
fmt.Println("int16:", b) // int16: 32767
fmt.Println("int32:", c) // int32: -2147483648
fmt.Println("int64:", d) // int64: 9223372036854775807
fmt.Println("int:", e) // int: -100
}
无符号整数
| 数据类型 | 位数 | 范围 | 说明 |
|---|---|---|---|
uint8 | 8 | 0 到 255 | 8 位无符号整数,占用 1 个字节 |
uint16 | 16 | 0 到 65535 | 16 位无符号整数,占用 2 个字节 |
uint32 | 32 | 0 到 4294967295 | 32 位无符号整数,占用 4 个字节 |
uint64 | 64 | 0 到 18446744073709551615 | 64 位无符号整数,占用 8 个字节 |
uint | 平台相关 | 32 位系统:0 到 4294967295;64 位系统:0 到 18446744073709551615 | 默认无符号整数类型,在 32 位系统上是 4 个字节,在 64 位系统上是 8 个字节 |
uintptr | 平台相关 | 与平台指针大小相同 | 用于存储指针的无符号整数,大小与平台的指针大小相同 |
package main
import "fmt"
func main() {
// 声明并初始化无符号整数
var a uint8 = 255
var b uint16 = 65535
var c uint32 = 4294967295
var d uint64 = 18446744073709551615
var e uint = 100 // 默认的 uint 类型
// 打印无符号整数
fmt.Println("uint8:", a) // uint8: 255
fmt.Println("uint16:", b) // uint16: 65535
fmt.Println("uint32:", c) // uint32: 4294967295
fmt.Println("uint64:", d) // uint64: 18446744073709551615
fmt.Println("uint:", e) // uint: 100
}
浮点数类型
| 数据类型 | 位数 | 精度范围(十进制数字) | 说明 |
|---|---|---|---|
float32 | 32 | 精度约为 6 到 7 位 | 32 位浮点数,适用于需要较小存储空间和较低精度的场景 |
float64 | 64 | 精度约为 15 到 16 位 | 64 位浮点数,适用于需要高精度计算的场景,如科学计算和金融计算 |
package main
import "fmt"
func main() {
// 声明并初始化浮点数
var a float32 = 3.1415926
var b float64 = 2.718281828459045
// 打印浮点数
fmt.Println("float32:", a) // float32: 3.1415925
fmt.Println("float64:", b) // float64: 2.718281828459045
}
需要注意的是,可能打印 a 会出现不是 3.1415926 的现象,由于 float32 在底层存储时,尾数位只有23位(不包含隐藏位,其余的1位符号位,8位指数位)所以可以保证小数点后的有效数字精度约为 6-7 位十进制数,故 float32 只能存储有限的位数,因此会进行截断或舍入,最终实际存储的值可能是 3.1415925
复数类型
| 数据类型 | 组成部分 | 精度 | 说明 |
|---|---|---|---|
complex64 | 由两个 float32 组成 | 精度约为 6 到 7 位 | 32 位复数类型,适用于需要较小存储空间和较低精度的场景 |
complex128 | 由两个 float64 组成 | 精度约为 15 到 16 位 | 64 位复数类型,适用于需要高精度计算的场景 |
package main
import "fmt"
func main() {
// 声明并初始化复数
var a complex64 = complex(3, 4) // 实部为 3,虚部为 4
var b complex128 = complex(5.5, 6.6) // 实部为 5.5,虚部为 6.6
// 打印复数
fmt.Println("complex64:", a) // complex64: (3+4i)
fmt.Println("complex128:", b) // complex128: (5.5+6.6i)
}
布尔类型(bool)
布尔类型(bool)用于表示逻辑值,它只有两个可能的值:true 和 false。
true:表示逻辑上的“真”。false:表示逻辑上的“假”。
布尔类型在 golang 中主要用于以下场景:
- 条件判断:在
if、for、switch等控制流语句中,布尔值用于决定程序的执行路径。 - 逻辑运算:布尔值可以参与逻辑运算,如
&&(逻辑与)、||(逻辑或)、!(逻辑非)。
package main
import "fmt"
func main() {
var isReady bool = true
var flag bool = false
fmt.Println("isReady:", isReady) // isReady: true
fmt.Println("flag:", flag) // flag: false
if isReady {
fmt.Println("Ready to go!") // Ready to go!
} else {
fmt.Println("Not ready yet.")
}
// 当isReady和flag都是true进入if代码段,否则执行else代码段
if isReady && flag {
fmt.Println("result is true")
} else {
fmt.Println("result is false") // result is false
}
}
字符串类型(string)
在 golang 语言中,字符串类型(string)用于表示文本数据。字符串在 golang 中是不可变的,这意味着一旦创建,字符串的内容不能被修改。
字符串是由字符组成的不可变序列,通常用双引号""或反引号```定义。双引号用于普通字符串,反引号用于原始字符串(Raw String)。
普通字符串可以包含 Unicode 字符,支持转义字符(如
、 等)。原始字符串不会处理转义字符,通常用于包含换行符或多行文本。
package main
import "fmt"
func main() {
// 普通字符串
var str1 string = "Hello, World!"
var str2 string = "Go语言支持中文字符"
var str3 string = "这是一个带有换行符的字符串
"
fmt.Println(str1)
fmt.Println(str2)
fmt.Println(str3)
// 原始字符串
var rawStr string = `这是一个原始字符串
它包含换行符和
这样的转义字符`
fmt.Println(rawStr)
}
字符串是不可变的,这意味着一旦创建,字符串的内容不能被修改。如果需要修改字符串,必须创建一个新的字符串。
package main
import "fmt"
func main() {
var str string = "Hello"
// str[0] = 'h' // 错误:字符串是不可变的
str = "hello" // 正确:重新分配一个新的字符串
fmt.Println(str) // hello
}
复合数据类型
数组(array)
数组是一种固定大小的序列类型,用于存储相同类型的元素。数组的大小在声明时确定,且不可变。数组元素下标从0开始。
- 固定大小:声明后大小不可变。
- 同类型元素:数组中的所有元素必须是相同的类型。
- 索引访问:可以通过索引访问和修改数组中的元素。
- 内存连续:数组的元素在内存中是连续存储的。
package main
import "fmt"
func main() {
// 声明一个长度为5的int数组
var arr [5]int = [5]int{1, 2, 3, 4, 5}
fmt.Println("数组:", arr)
fmt.Println("数组长度:", len(arr)) // 获取数组长度5
// 修改数组元素
arr[0] = 10
fmt.Println("修改后的数组:", arr) // [10 2 3 4 5]
}
切片(slice)
切片是基于数组的动态数据结构,可以动态增长和缩减。切片提供了更灵活的数组操作。
- 动态大小:可以动态增长和缩减。
- 底层基于数组:切片是对底层数组的引用。
- 丰富的操作:支持
append、copy、len、cap等操作。 - 切片操作:可以通过切片操作符
[:]创建新的切片。
package main
import "fmt"
func main() {
// 声明一个切片
slice := []int{1, 2, 3, 4, 5}
fmt.Println("切片:", slice)
fmt.Println("切片长度:", len(slice)) // 获取切片长度5
// 向切片追加元素
slice = append(slice, 6)
fmt.Println("追加后的切片:", slice) // 追加后的切片: [1 2 3 4 5 6]
// 切片操作
slice = slice[1:3] // 从下标1开始到下标3结束(不包含下标3)
fmt.Println("切片操作后的切片:", slice) // 切片操作后的切片: [2 3]
}
映射(map)
映射是一种键值对的集合,键是唯一的,值可以是任意类型。
- 键的唯一性:映射中的键必须是唯一的。如果尝试向映射中添加一个已经存在的键,其对应的值会被覆盖。
- 动态大小:映射的大小是动态的,可以根据需要动态添加、删除或修改键值对。
- 键值对:键的类型必须是可比较的,例如基本类型、指针、接口、通道、结构体等。不可比较的类型(如切片、映射、函数)不能作为键;值可以是任意类型,包括基本类型(如
int、string)、结构体、切片、映射等;
package main
import "fmt"
func main() {
// 创建一个映射,键是string类型,值是int类型
m := make(map[string]int)
m["Alice"] = 30
m["Bob"] = 25
// 获取值
fmt.Println("Alice's age:", m["Alice"]) // Alice's age: 30
// 检查键是否存在
if age, ok := m["Charlie"]; ok {
fmt.Println("Charlie's age:", age)
} else {
fmt.Println("Charlie is not in the map") // Charlie is not in the map
}
}
结构体(struct)
结构体是一种自定义的数据类型,用于组合不同类型的数据。
- 自定义类型:可以包含不同类型的数据字段。
- 方法绑定:可以为结构体定义方法。
- 嵌入:可以嵌入其他结构体。
package main
import "fmt"
// 自定义结构体
type Person struct {
Name string
Age int
}
// 结构体Person的方法,方法名称时SayHello
func (p Person) SayHello() string {
return "Hello, my name is " + p.Name
}
func main() {
// 声明一个结构体变量
p := Person{Name: "Alice", Age: 30}
fmt.Println("结构体:", p) // 结构体: {Alice 30}
fmt.Println("结构体的Name字段:", p.Name) // 结构体的Name字段: Alice
// 修改结构体字段
p.Age = 31
fmt.Println("修改后的结构体:", p) // 修改后的结构体: {Alice 31}
// 调用结构体方法
fmt.Println(p.SayHello()) // Hello, my name is Alice
}
指针(pointer)
指针存储变量的内存地址,通过指针可以间接访问和修改变量的值。
- 存储内存地址:指针存储变量的内存地址。
- 间接访问:可以通过指针间接访问和修改变量的值。
- 指针类型:指针类型为
*T,其中T是基础类型。
package main
import "fmt"
func main() {
var a int = 10
var p *int = &a // 声明一个指针p,指向变量a的地址
fmt.Println("变量a的值:", a) // 变量a的值: 10
fmt.Println("指针p指向的地址:", p) // 指针p指向的地址: 0xc0000120e0
fmt.Println("指针p指向地址的值:", *p) // 指针p指向地址的值: 10
// 通过指针修改变量a的值
*p = 20
fmt.Println("修改后的变量a的值:", a) // 修改后的变量a的值: 20
}
指针指向自定义结构体类型,代码如下所示:
package main
import "fmt"
// 自定义结构体
type Person struct {
Name string
Age int
}
// 结构体Person的方法,方法名称时SayHello
func (p Person) SayHello() string {
return "Hello, my name is " + p.Name
}
func main() {
persion := Person{Name: "Bob", Age: 18}
var pPtr *Person = &persion
fmt.Println("指针pPtr指向地址的值:", *pPtr) // 指针pPtr指向地址的值: {Bob 18}
pPtr.Age = 19
fmt.Println("修改后的值:", persion) // 修改后的值: {Bob 19}
fmt.Println(pPtr.SayHello()) // Hello, my name is Bob
}
函数(function)
函数是一段可以重复使用的代码,用于执行特定的任务。
- 参数和返回值:可以有参数和返回值。
- 多返回值:支持多返回值。
- 作为变量传递:函数可以作为变量传递。
package main
import "fmt"
func add(a, b int) int {
return a + b // 返回两个整数的和
}
func main() {
result := add(5, 3) // 调用函数
fmt.Println("函数返回的结果:", result) // 函数返回的结果: 8
}
接口(interface)
接口定义了一组方法,类型通过实现这些方法来满足接口。接口是一种类型抽象。
- 方法签名:接口定义了一组方法签名。
- 动态绑定:类型通过实现接口中的方法来满足接口。
package main
import "fmt"
type Animal interface {
Speak() string // 定义接口方法
}
type Dog struct {
Name string
}
// Dog结构体实现了接口Animal的Speak方法
func (d Dog) Speak() string {
return "Woof!"
}
func main() {
var animal Animal = Dog{Name: "Buddy"} // 声明一个接口变量
fmt.Println("动物说话:", animal.Speak()) // 动物说话: Woof!
}
通道(channel)
通道用于在 golang 协程( goroutine )之间通信,可以发送和接收数据。
- 协程间通信:用于协程间的通信。
- 同步和异步操作:支持同步和异步操作。
- 带缓冲通道:可以是带缓冲的通道。
发送和接收数据
- 发送数据:
ch <- value。 - 接收数据:
value := <-ch。 - 安全接收:
value, ok := <-ch,其中ok是一个布尔值,如果通道已经关闭且没有更多数据可接收,ok将会是false。
关闭通道
- 通道可以通过
close(ch)函数来关闭。一旦通道被关闭,就不能再向其发送数据,但仍然可以从通道中接收已有的数据。 - 注意:通常只有发送方应该关闭通道,因为关闭通道是一种通知接收方不再有新数据到来的信号。
package main
import (
"fmt"
"time"
)
func main() {
ch := make(chan int) // 创建一个通道
// 启动一个协程,向通道ch中发送数据
go func() {
ch <- 42
close(ch) // 发送完数据后关闭通道
}()
val := <-ch // 从通道接收数据
fmt.Println("从通道接收到的数据:", val) // 从通道接收到的数据: 42
_, ok := <-ch
if !ok {
fmt.Println("通道已关闭")
}
time.Sleep(1 * time.Second) // 等待协程完成
}
类型转换
类型转换是指将一个类型的值转换为另一个类型的值。在 golang 语言中,类型转换是显式的,需要明确指定目标类型。
- 显式转换:类型转换必须显式进行,不能自动转换。
- 目标类型必须明确:转换时需要明确指定目标类型。
- 转换规则:只有类型兼容的值才能进行转换。
基本类型转换
package main
import "fmt"
func main() {
var a int = 10
var b float64 = float64(a) // 将int转换为float64
fmt.Println("转换后的值:", b) // 转换后的值: 10
var c float64 = 3.14
var d int = int(c) // 将float64转换为int
fmt.Println("转换后的值:", d) // 转换后的值: 3
}
将高精度类型转换为低精度类型时,可能会导致精度损失。例如上面给出的代码中所示,将float64转换为int时,小数部分会被截断。
另外针对基本类型转换时需要保证类型兼容的值,例如,不能将string直接转换为int。
需要注意,当对一个类型使用 type 关键字定义别名之后,再进行类型转换时编译器会认为不是相同的类型,需要显示的类型转换
package main
import "fmt"
func main() {
type MyInt int
var a MyInt = 1
// error: cannot use a (variable of type MyInt) as int value in variable
// var b int = a
var b int = int(a)
fmt.Println(a, b) // 1 1
}
切片和数组转换
package main
import "fmt"
func main() {
var arr [5]int = [5]int{1, 2, 3, 4, 5}
var slice []int = arr[:] // 将数组转换为切片
fmt.Println("切片:", slice) // 切片: [1 2 3 4 5]
}
接口类型转换
接口类型转换需要使用类型断言(Type Assertion)用于将接口类型转换为具体的类型。类型断言是 golang 语言中处理接口类型转换的一种方式,它允许在运行时检查接口变量是否实现了某个具体类型,并将其转换为该类型。
value, ok := interfaceValue.(T)
interfaceValue是接口类型的变量。T是目标类型。value是转换后的值。ok是一个布尔值,表示转换是否成功。
单值形式
value := interfaceValue.(T)
- 如果转换成功,
value是转换后的值。 - 如果转换失败,程序会触发
panic。
多值形式
value, ok := interfaceValue.(T)
- 如果转换成功,
value是转换后的值,ok为true。 - 如果转换失败,
value是目标类型的零值,ok为false。
注意事项
- 类型兼容性:只有当接口变量实际存储的值是目标类型时,类型断言才会成功。
- 避免
panic:在不确定接口变量具体类型时,建议使用双值形式进行类型断言,以避免程序panic。 - 嵌入类型:如果接口变量存储的是嵌入类型,类型断言也可以成功。例如,
Animal接口存储的是*Dog类型时,animal.(*Dog)也是有效的。
代码示例
package main
import "fmt"
type Animal interface {
Speak() string
}
type Dog struct{}
func (d Dog) Speak() string {
return "Woof!"
}
func main() {
// 单值形式
var animal1 Animal = Dog{}
dog1 := animal1.(Dog) // 单值形式,如果失败会panic
fmt.Println("动物说话:", dog1.Speak())
// 多值形式
var animal2 Animal = Dog{}
if dog2, ok := animal2.(Dog); ok {
fmt.Println("动物说话:", dog2.Speak())
} else {
fmt.Println("类型转换失败")
}
}
类型推断
类型推断是指编译器根据上下文自动推断变量的类型。在 golang 语言中,类型推断主要通过短变量声明(:=)和函数返回值实现。
- 短变量声明:使用
:=声明变量时,编译器会根据赋值的值自动推断变量的类型。 - 函数返回值:函数返回值的类型由函数签名决定,编译器会根据返回值的类型自动推断变量的类型。
- 简洁性:减少代码冗余,提高代码可读性。
短变量声明
package main
import "fmt"
func main() {
a := 10 // 编译器推断a的类型为int
b := "Hello" // 编译器推断b的类型为string
fmt.Println(a, b) // 10 Hello
}
注意::=只能在函数内部使用,不能在函数外部使用。
函数返回值
package main
import "fmt"
// 函数的返回值是int类型
func add(a, b int) int {
return a + b
}
func main() {
result := add(5, 3) // 编译器推断result的类型为int
fmt.Println("函数返回的结果:", result) // 函数返回的结果: 8
}





U8W/U8W-Mini使用与常见问题解决
QT多线程的5种用法,通过使用线程解决UI主界面的耗时操作代码,防止界面卡死。...
stm32使用HAL库配置串口中断收发数据(保姆级教程)
分享几个国内免费的ChatGPT镜像网址(亲测有效)
Allegro16.6差分等长设置及走线总结