Files
golang/golang-learning/01-basics/04-data-types.go
2025-08-24 01:01:26 +08:00

414 lines
12 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
04-data-types.go - Go 语言数据类型详解
学习目标:
1. 掌握 Go 的基本数据类型
2. 理解不同数值类型的范围和用途
3. 学会字符串和字符的处理
4. 了解类型转换的方法
5. 掌握复合数据类型的基础
知识点:
- 整数类型 (int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64)
- 浮点类型 (float32, float64)
- 复数类型 (complex64, complex128)
- 布尔类型 (bool)
- 字符串类型 (string)
- 字符类型 (byte, rune)
- 类型转换
- 类型别名
*/
package main
import (
"fmt"
"math"
"unsafe"
)
func main() {
fmt.Println("=== Go 语言数据类型详解 ===\n")
// 演示整数类型
demonstrateIntegerTypes()
// 演示浮点类型
demonstrateFloatTypes()
// 演示复数类型
demonstrateComplexTypes()
// 演示布尔类型
demonstrateBooleanType()
// 演示字符串类型
demonstrateStringType()
// 演示字符类型
demonstrateCharacterTypes()
// 演示类型转换
demonstrateTypeConversion()
// 演示类型信息
demonstrateTypeInfo()
}
// demonstrateIntegerTypes 演示整数类型
func demonstrateIntegerTypes() {
fmt.Println("1. 整数类型:")
// 有符号整数
var i8 int8 = 127 // -128 到 127
var i16 int16 = 32767 // -32768 到 32767
var i32 int32 = 2147483647 // -2^31 到 2^31-1
var i64 int64 = 9223372036854775807 // -2^63 到 2^63-1
fmt.Printf(" 有符号整数:\n")
fmt.Printf(" int8: %d (大小: %d 字节)\n", i8, unsafe.Sizeof(i8))
fmt.Printf(" int16: %d (大小: %d 字节)\n", i16, unsafe.Sizeof(i16))
fmt.Printf(" int32: %d (大小: %d 字节)\n", i32, unsafe.Sizeof(i32))
fmt.Printf(" int64: %d (大小: %d 字节)\n", i64, unsafe.Sizeof(i64))
// 无符号整数
var ui8 uint8 = 255 // 0 到 255
var ui16 uint16 = 65535 // 0 到 65535
var ui32 uint32 = 4294967295 // 0 到 2^32-1
var ui64 uint64 = 18446744073709551615 // 0 到 2^64-1
fmt.Printf(" 无符号整数:\n")
fmt.Printf(" uint8: %d (大小: %d 字节)\n", ui8, unsafe.Sizeof(ui8))
fmt.Printf(" uint16: %d (大小: %d 字节)\n", ui16, unsafe.Sizeof(ui16))
fmt.Printf(" uint32: %d (大小: %d 字节)\n", ui32, unsafe.Sizeof(ui32))
fmt.Printf(" uint64: %d (大小: %d 字节)\n", ui64, unsafe.Sizeof(ui64))
// 平台相关的整数类型
var i int = 2147483647 // 32位系统上是int3264位系统上是int64
var ui uint = 4294967295 // 32位系统上是uint3264位系统上是uint64
var uiptr uintptr = 0x12345678 // 存储指针的整数类型
fmt.Printf(" 平台相关类型:\n")
fmt.Printf(" int: %d (大小: %d 字节)\n", i, unsafe.Sizeof(i))
fmt.Printf(" uint: %d (大小: %d 字节)\n", ui, unsafe.Sizeof(ui))
fmt.Printf(" uintptr: 0x%x (大小: %d 字节)\n", uiptr, unsafe.Sizeof(uiptr))
// 整数的不同表示法
fmt.Printf(" 整数的不同表示法:\n")
decimal := 42 // 十进制
binary := 0b101010 // 二进制 (Go 1.13+)
octal := 0o52 // 八进制 (Go 1.13+)
hexadecimal := 0x2A // 十六进制
fmt.Printf(" 十进制: %d\n", decimal)
fmt.Printf(" 二进制: %d (0b%b)\n", binary, binary)
fmt.Printf(" 八进制: %d (0o%o)\n", octal, octal)
fmt.Printf(" 十六进制: %d (0x%X)\n", hexadecimal, hexadecimal)
fmt.Println()
}
// demonstrateFloatTypes 演示浮点类型
func demonstrateFloatTypes() {
fmt.Println("2. 浮点类型:")
// float32 和 float64
var f32 float32 = 3.14159
var f64 float64 = 3.141592653589793
fmt.Printf(" 基本浮点类型:\n")
fmt.Printf(" float32: %.7f (大小: %d 字节)\n", f32, unsafe.Sizeof(f32))
fmt.Printf(" float64: %.15f (大小: %d 字节)\n", f64, unsafe.Sizeof(f64))
// 浮点数的特殊值
fmt.Printf(" 特殊浮点值:\n")
fmt.Printf(" 正无穷: %f\n", math.Inf(1))
fmt.Printf(" 负无穷: %f\n", math.Inf(-1))
fmt.Printf(" NaN: %f\n", math.NaN())
// 浮点数的科学计数法
scientific1 := 1.23e4 // 1.23 * 10^4 = 12300
scientific2 := 1.23e-4 // 1.23 * 10^-4 = 0.000123
fmt.Printf(" 科学计数法:\n")
fmt.Printf(" 1.23e4 = %f\n", scientific1)
fmt.Printf(" 1.23e-4 = %f\n", scientific2)
// 浮点数精度问题
fmt.Printf(" 精度问题演示:\n")
var a float64 = 0.1
var b float64 = 0.2
var c float64 = 0.3
fmt.Printf(" 0.1 + 0.2 = %.17f\n", a+b)
fmt.Printf(" 0.3 = %.17f\n", c)
fmt.Printf(" 0.1 + 0.2 == 0.3: %t\n", a+b == c)
fmt.Println()
}
// demonstrateComplexTypes 演示复数类型
func demonstrateComplexTypes() {
fmt.Println("3. 复数类型:")
// complex64 和 complex128
var c64 complex64 = 3 + 4i
var c128 complex128 = 5 + 6i
fmt.Printf(" 基本复数类型:\n")
fmt.Printf(" complex64: %v (大小: %d 字节)\n", c64, unsafe.Sizeof(c64))
fmt.Printf(" complex128: %v (大小: %d 字节)\n", c128, unsafe.Sizeof(c128))
// 复数的创建方式
c1 := 1 + 2i // 直接创建
c2 := complex(3, 4) // 使用 complex 函数
c3 := complex(float64(5), 6) // 指定类型
fmt.Printf(" 复数创建方式:\n")
fmt.Printf(" 直接创建: %v\n", c1)
fmt.Printf(" complex函数: %v\n", c2)
fmt.Printf(" 指定类型: %v\n", c3)
// 复数的实部和虚部
fmt.Printf(" 复数的实部和虚部:\n")
fmt.Printf(" %v 的实部: %.1f\n", c2, real(c2))
fmt.Printf(" %v 的虚部: %.1f\n", c2, imag(c2))
// 复数运算
sum := c1 + c2
product := c1 * c2
fmt.Printf(" 复数运算:\n")
fmt.Printf(" %v + %v = %v\n", c1, c2, sum)
fmt.Printf(" %v * %v = %v\n", c1, c2, product)
fmt.Println()
}
// demonstrateBooleanType 演示布尔类型
func demonstrateBooleanType() {
fmt.Println("4. 布尔类型:")
var b1 bool = true
var b2 bool = false
var b3 bool // 零值是 false
fmt.Printf(" 基本布尔值:\n")
fmt.Printf(" b1: %t (大小: %d 字节)\n", b1, unsafe.Sizeof(b1))
fmt.Printf(" b2: %t\n", b2)
fmt.Printf(" b3 (零值): %t\n", b3)
// 布尔运算
fmt.Printf(" 布尔运算:\n")
fmt.Printf(" true && false = %t\n", true && false)
fmt.Printf(" true || false = %t\n", true || false)
fmt.Printf(" !true = %t\n", !true)
fmt.Printf(" !false = %t\n", !false)
// 比较运算产生布尔值
x, y := 10, 20
fmt.Printf(" 比较运算:\n")
fmt.Printf(" %d == %d: %t\n", x, y, x == y)
fmt.Printf(" %d != %d: %t\n", x, y, x != y)
fmt.Printf(" %d < %d: %t\n", x, y, x < y)
fmt.Printf(" %d > %d: %t\n", x, y, x > y)
fmt.Printf(" %d <= %d: %t\n", x, y, x <= y)
fmt.Printf(" %d >= %d: %t\n", x, y, x >= y)
fmt.Println()
}
// demonstrateStringType 演示字符串类型
func demonstrateStringType() {
fmt.Println("5. 字符串类型:")
var s1 string = "Hello, World!"
var s2 string = "你好,世界!"
var s3 string // 零值是空字符串 ""
fmt.Printf(" 基本字符串:\n")
fmt.Printf(" s1: \"%s\" (长度: %d, 大小: %d 字节)\n", s1, len(s1), unsafe.Sizeof(s1))
fmt.Printf(" s2: \"%s\" (长度: %d)\n", s2, len(s2))
fmt.Printf(" s3 (零值): \"%s\"\n", s3)
// 字符串是不可变的
fmt.Printf(" 字符串特性:\n")
fmt.Printf(" 字符串是不可变的immutable\n")
fmt.Printf(" 字符串是 UTF-8 编码的\n")
// 字符串操作
fmt.Printf(" 字符串操作:\n")
concatenated := s1 + " " + s2
fmt.Printf(" 连接: \"%s\"\n", concatenated)
// 原始字符串字面量
rawString := `这是一个原始字符串
可以包含换行符
和 "双引号" 以及 \n 这样的字符`
fmt.Printf(" 原始字符串:\n")
fmt.Printf(" %s\n", rawString)
// 字符串转义序列
escaped := "制表符:\t换行符:\n引号:\"反斜杠:\\"
fmt.Printf(" 转义序列:\n")
fmt.Printf(" %s\n", escaped)
// 字符串索引和切片
fmt.Printf(" 字符串索引和切片:\n")
str := "Hello"
fmt.Printf(" str[0]: %c (字节值: %d)\n", str[0], str[0])
fmt.Printf(" str[1:4]: \"%s\"\n", str[1:4])
fmt.Printf(" str[:3]: \"%s\"\n", str[:3])
fmt.Printf(" str[2:]: \"%s\"\n", str[2:])
fmt.Println()
}
// demonstrateCharacterTypes 演示字符类型
func demonstrateCharacterTypes() {
fmt.Println("6. 字符类型:")
// byte 类型uint8 的别名)
var b byte = 'A'
fmt.Printf(" byte 类型:\n")
fmt.Printf(" 字符 'A': %c (ASCII值: %d, 大小: %d 字节)\n", b, b, unsafe.Sizeof(b))
// rune 类型int32 的别名,用于 Unicode 字符)
var r1 rune = 'A'
var r2 rune = '中'
var r3 rune = '🚀'
fmt.Printf(" rune 类型:\n")
fmt.Printf(" 字符 'A': %c (Unicode值: %d, 大小: %d 字节)\n", r1, r1, unsafe.Sizeof(r1))
fmt.Printf(" 字符 '中': %c (Unicode值: %d)\n", r2, r2)
fmt.Printf(" 字符 '🚀': %c (Unicode值: %d)\n", r3, r3)
// 字符串遍历
fmt.Printf(" 字符串遍历:\n")
str := "Hello世界"
fmt.Printf(" 按字节遍历:\n")
for i := 0; i < len(str); i++ {
fmt.Printf(" [%d]: %c (%d)\n", i, str[i], str[i])
}
fmt.Printf(" 按字符遍历 (range):\n")
for i, r := range str {
fmt.Printf(" [%d]: %c (%d)\n", i, r, r)
}
// Unicode 转义
fmt.Printf(" Unicode 转义:\n")
unicode1 := '\u4e2d' // 中
unicode2 := '\U0001F680' // 🚀
fmt.Printf(" \\u4e2d: %c\n", unicode1)
fmt.Printf(" \\U0001F680: %c\n", unicode2)
fmt.Println()
}
// demonstrateTypeConversion 演示类型转换
func demonstrateTypeConversion() {
fmt.Println("7. 类型转换:")
// 数值类型转换
var i int = 42
var f float64 = float64(i) // int 转 float64
var ui uint = uint(i) // int 转 uint
fmt.Printf(" 数值类型转换:\n")
fmt.Printf(" int %d -> float64 %.1f\n", i, f)
fmt.Printf(" int %d -> uint %d\n", i, ui)
// 注意Go 不支持隐式类型转换
var i32 int32 = 100
var i64 int64 = int64(i32) // 必须显式转换
fmt.Printf(" int32 %d -> int64 %d\n", i32, i64)
// 字符串和数值转换需要使用 strconv 包
// 这里只演示字符和数值的转换
var ch byte = 65
var chStr string = string(ch)
fmt.Printf(" 字符转换:\n")
fmt.Printf(" byte %d -> string \"%s\"\n", ch, chStr)
var r rune = 20013 // '中' 的 Unicode 值
var rStr string = string(r)
fmt.Printf(" rune %d -> string \"%s\"\n", r, rStr)
// 字符串转字节切片和字符切片
str := "Hello世界"
bytes := []byte(str)
runes := []rune(str)
fmt.Printf(" 字符串转换:\n")
fmt.Printf(" string -> []byte: %v\n", bytes)
fmt.Printf(" string -> []rune: %v\n", runes)
fmt.Printf(" []byte -> string: \"%s\"\n", string(bytes))
fmt.Printf(" []rune -> string: \"%s\"\n", string(runes))
fmt.Println()
}
// demonstrateTypeInfo 演示类型信息
func demonstrateTypeInfo() {
fmt.Println("8. 类型信息:")
// 使用 %T 打印类型信息
var i int = 42
var f float64 = 3.14
var s string = "Hello"
var b bool = true
var c complex128 = 1 + 2i
fmt.Printf(" 类型信息:\n")
fmt.Printf(" %v 的类型: %T\n", i, i)
fmt.Printf(" %v 的类型: %T\n", f, f)
fmt.Printf(" \"%v\" 的类型: %T\n", s, s)
fmt.Printf(" %v 的类型: %T\n", b, b)
fmt.Printf(" %v 的类型: %T\n", c, c)
// 类型别名
type MyInt int
type MyString string
var mi MyInt = 100
var ms MyString = "自定义类型"
fmt.Printf(" 自定义类型:\n")
fmt.Printf(" %v 的类型: %T\n", mi, mi)
fmt.Printf(" \"%v\" 的类型: %T\n", ms, ms)
// 类型别名和原类型的转换
var normalInt int = int(mi) // 需要显式转换
fmt.Printf(" MyInt -> int: %d\n", normalInt)
fmt.Println()
}
/*
运行这个程序:
go run 04-data-types.go
学习要点:
1. Go 有丰富的基本数据类型,包括整数、浮点、复数、布尔、字符串
2. 整数类型有有符号和无符号之分,大小从 8 位到 64 位
3. int 和 uint 的大小取决于平台32位或64位
4. 浮点数有精度限制,比较时要注意精度问题
5. 字符串是 UTF-8 编码的,不可变的
6. byte 用于 ASCII 字符rune 用于 Unicode 字符
7. Go 不支持隐式类型转换,必须显式转换
8. 可以定义类型别名,但需要显式转换
选择类型的建议:
1. 整数:一般使用 int需要特定大小时使用 int8/16/32/64
2. 浮点:一般使用 float64性能要求高时使用 float32
3. 字符ASCII 字符用 byteUnicode 字符用 rune
4. 字符串:使用 string需要修改时转换为 []byte 或 []rune
注意事项:
1. 不同类型之间不能直接运算,必须转换为相同类型
2. 浮点数比较要考虑精度问题
3. 字符串索引访问的是字节,不是字符
4. 使用 range 遍历字符串可以正确处理 Unicode 字符
*/