1.2.2 基本数据类型 #
Go 语言提供了丰富的基本数据类型,包括数值类型、布尔类型、字符串类型等。理解这些基本类型的特性和使用方法是掌握 Go 语言的重要基础。
数值类型 #
1. 整数类型 #
Go 语言提供了多种整数类型,分为有符号和无符号两类:
package main
import (
"fmt"
"unsafe"
)
func main() {
// 有符号整数类型
var i8 int8 = 127 // -128 到 127
var i16 int16 = 32767 // -32768 到 32767
var i32 int32 = 2147483647
var i64 int64 = 9223372036854775807
// 无符号整数类型
var ui8 uint8 = 255 // 0 到 255
var ui16 uint16 = 65535 // 0 到 65535
var ui32 uint32 = 4294967295
var ui64 uint64 = 18446744073709551615
// 平台相关的整数类型
var i int = 2147483647 // 32位系统为int32,64位系统为int64
var ui uint = 4294967295 // 32位系统为uint32,64位系统为uint64
// 特殊类型
var ptr uintptr = 0x12345678 // 存储指针的整数类型
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))
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))
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", ptr, unsafe.Sizeof(ptr))
}
2. 浮点数类型 #
Go 语言提供了两种浮点数类型:
package main
import (
"fmt"
"math"
"unsafe"
)
func main() {
// 浮点数类型
var f32 float32 = 3.14159
var f64 float64 = 3.141592653589793
fmt.Printf("float32: %.7f (大小: %d字节)\n", f32, unsafe.Sizeof(f32))
fmt.Printf("float64: %.15f (大小: %d字节)\n", f64, unsafe.Sizeof(f64))
// 浮点数的特殊值
fmt.Printf("正无穷: %f\n", math.Inf(1))
fmt.Printf("负无穷: %f\n", math.Inf(-1))
fmt.Printf("NaN: %f\n", math.NaN())
// 浮点数精度问题
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)
// 正确的浮点数比较
epsilon := 1e-9
fmt.Printf("近似相等: %t\n", math.Abs((a+b)-c) < epsilon)
}
3. 复数类型 #
Go 语言原生支持复数:
package main
import (
"fmt"
"math/cmplx"
)
func main() {
// 复数类型
var c64 complex64 = 3 + 4i
var c128 complex128 = 5 + 12i
fmt.Printf("complex64: %v\n", c64)
fmt.Printf("complex128: %v\n", c128)
// 复数运算
sum := c64 + complex64(c128)
product := c64 * complex64(c128)
fmt.Printf("和: %v\n", sum)
fmt.Printf("积: %v\n", product)
// 复数函数
fmt.Printf("c128的实部: %.2f\n", real(c128))
fmt.Printf("c128的虚部: %.2f\n", imag(c128))
fmt.Printf("c128的模: %.2f\n", cmplx.Abs(c128))
fmt.Printf("c128的相位: %.2f弧度\n", cmplx.Phase(c128))
// 从实部和虚部构造复数
c := complex(3.0, 4.0)
fmt.Printf("构造的复数: %v\n", c)
}
布尔类型 #
package main
import "fmt"
func main() {
// 布尔类型
var isTrue bool = true
var isFalse bool = false
var defaultBool bool // 零值为 false
fmt.Printf("isTrue: %t\n", isTrue)
fmt.Printf("isFalse: %t\n", isFalse)
fmt.Printf("defaultBool: %t\n", defaultBool)
// 布尔运算
fmt.Printf("true && false: %t\n", true && false)
fmt.Printf("true || false: %t\n", true || false)
fmt.Printf("!true: %t\n", !true)
// 比较运算返回布尔值
a, b := 10, 20
fmt.Printf("%d > %d: %t\n", a, b, a > b)
fmt.Printf("%d == %d: %t\n", a, b, a == b)
fmt.Printf("%d != %d: %t\n", a, b, a != b)
// 布尔值不能与数字直接转换
// var num int = int(isTrue) // 错误
// 需要显式转换
var num int
if isTrue {
num = 1
} else {
num = 0
}
fmt.Printf("布尔转数字: %d\n", num)
}
字符串类型 #
1. 字符串基础 #
package main
import (
"fmt"
"unicode/utf8"
)
func main() {
// 字符串声明
var str1 string = "Hello, World!"
str2 := "你好,世界!"
var emptyStr string // 零值为空字符串 ""
fmt.Printf("str1: %s (长度: %d字节)\n", str1, len(str1))
fmt.Printf("str2: %s (长度: %d字节)\n", str2, len(str2))
fmt.Printf("emptyStr: %q (长度: %d字节)\n", emptyStr, len(emptyStr))
// UTF-8 字符计数
fmt.Printf("str2的字符数: %d\n", utf8.RuneCountInString(str2))
// 字符串是不可变的
// str1[0] = 'h' // 错误:不能修改字符串
// 字符串拼接
greeting := str1 + " " + str2
fmt.Printf("拼接结果: %s\n", greeting)
// 多行字符串
multiLine := `这是一个
多行字符串
可以包含换行符`
fmt.Printf("多行字符串:\n%s\n", multiLine)
}
2. 字符串和字节 #
package main
import "fmt"
func main() {
str := "Hello, 世界"
// 字符串转字节切片
bytes := []byte(str)
fmt.Printf("字节切片: %v\n", bytes)
fmt.Printf("字节切片长度: %d\n", len(bytes))
// 字节切片转字符串
newStr := string(bytes)
fmt.Printf("转换回字符串: %s\n", newStr)
// 遍历字符串的字节
fmt.Print("按字节遍历: ")
for i := 0; i < len(str); i++ {
fmt.Printf("%02x ", str[i])
}
fmt.Println()
// 遍历字符串的字符(rune)
fmt.Print("按字符遍历: ")
for _, r := range str {
fmt.Printf("%c ", r)
}
fmt.Println()
// 获取字符串中的单个字符
fmt.Printf("第一个字节: %c\n", str[0])
// 字符串切片
fmt.Printf("子字符串: %s\n", str[0:5])
fmt.Printf("从索引2开始: %s\n", str[2:])
fmt.Printf("到索引5结束: %s\n", str[:5])
}
字符类型(rune 和 byte) #
package main
import (
"fmt"
"unicode"
)
func main() {
// byte 类型(uint8 的别名)
var b byte = 'A'
fmt.Printf("byte: %c (值: %d)\n", b, b)
// rune 类型(int32 的别名,表示 Unicode 码点)
var r rune = '中'
fmt.Printf("rune: %c (值: %d, Unicode: U+%04X)\n", r, r, r)
// 字符字面量
char1 := 'a' // rune 类型
char2 := '\n' // 换行符
char3 := '\u4e2d' // Unicode 转义序列(中)
char4 := '\U00004e2d' // 长 Unicode 转义序列
fmt.Printf("char1: %c\n", char1)
fmt.Printf("char2: %q\n", char2)
fmt.Printf("char3: %c\n", char3)
fmt.Printf("char4: %c\n", char4)
// 字符分类
testChars := []rune{'A', 'a', '1', '中', ' ', '\n'}
for _, ch := range testChars {
fmt.Printf("字符 %c: ", ch)
if unicode.IsLetter(ch) {
fmt.Print("字母 ")
}
if unicode.IsDigit(ch) {
fmt.Print("数字 ")
}
if unicode.IsSpace(ch) {
fmt.Print("空白 ")
}
if unicode.IsUpper(ch) {
fmt.Print("大写 ")
}
if unicode.IsLower(ch) {
fmt.Print("小写 ")
}
fmt.Println()
}
}
类型转换 #
1. 基本类型转换 #
package main
import (
"fmt"
"strconv"
)
func main() {
// 数值类型转换
var i int = 42
var f float64 = float64(i)
var ui uint = uint(i)
fmt.Printf("int: %d\n", i)
fmt.Printf("float64: %.2f\n", f)
fmt.Printf("uint: %d\n", ui)
// 浮点数转整数(截断)
var pi float64 = 3.14159
var intPi int = int(pi)
fmt.Printf("π: %.5f -> %d\n", pi, intPi)
// 类型转换可能导致数据丢失
var bigInt int64 = 1000000000000
var smallInt int32 = int32(bigInt) // 数据丢失
fmt.Printf("大整数: %d -> 小整数: %d\n", bigInt, smallInt)
// 字符串和数值转换
str := "123"
num, err := strconv.Atoi(str)
if err != nil {
fmt.Printf("转换错误: %v\n", err)
} else {
fmt.Printf("字符串 %s -> 整数 %d\n", str, num)
}
// 数值转字符串
numStr := strconv.Itoa(456)
fmt.Printf("整数 456 -> 字符串 %s\n", numStr)
// 更多字符串转换
floatStr := "3.14159"
floatNum, err := strconv.ParseFloat(floatStr, 64)
if err != nil {
fmt.Printf("转换错误: %v\n", err)
} else {
fmt.Printf("字符串 %s -> 浮点数 %.5f\n", floatStr, floatNum)
}
// 浮点数转字符串
floatToStr := strconv.FormatFloat(3.14159, 'f', 2, 64)
fmt.Printf("浮点数 3.14159 -> 字符串 %s\n", floatToStr)
}
2. 高级类型转换 #
package main
import (
"fmt"
"reflect"
"strconv"
)
func main() {
// 接口类型转换(类型断言)
var i interface{} = 42
// 类型断言
if num, ok := i.(int); ok {
fmt.Printf("接口值是整数: %d\n", num)
}
// 类型开关
switch v := i.(type) {
case int:
fmt.Printf("整数类型: %d\n", v)
case string:
fmt.Printf("字符串类型: %s\n", v)
case float64:
fmt.Printf("浮点数类型: %.2f\n", v)
default:
fmt.Printf("未知类型: %T\n", v)
}
// 使用反射进行类型转换
value := reflect.ValueOf(42)
fmt.Printf("反射类型: %s\n", value.Type())
fmt.Printf("反射值: %v\n", value.Interface())
// 字符串和布尔值转换
boolStr := "true"
boolVal, err := strconv.ParseBool(boolStr)
if err != nil {
fmt.Printf("转换错误: %v\n", err)
} else {
fmt.Printf("字符串 %s -> 布尔值 %t\n", boolStr, boolVal)
}
// 布尔值转字符串
boolToStr := strconv.FormatBool(true)
fmt.Printf("布尔值 true -> 字符串 %s\n", boolToStr)
}
类型别名和自定义类型 #
package main
import "fmt"
// 类型别名
type MyInt = int
type MyString = string
// 自定义类型
type UserID int
type UserName string
type Temperature float64
// 为自定义类型定义方法
func (t Temperature) Celsius() float64 {
return float64(t)
}
func (t Temperature) Fahrenheit() float64 {
return float64(t)*9/5 + 32
}
func (t Temperature) String() string {
return fmt.Sprintf("%.1f°C", t.Celsius())
}
func main() {
// 类型别名的使用
var mi MyInt = 42
var ms MyString = "hello"
// 类型别名可以直接赋值给原类型
var i int = mi
var s string = ms
fmt.Printf("MyInt: %d, int: %d\n", mi, i)
fmt.Printf("MyString: %s, string: %s\n", ms, s)
// 自定义类型的使用
var uid UserID = 12345
var uname UserName = "张三"
var temp Temperature = 25.5
fmt.Printf("用户ID: %d\n", uid)
fmt.Printf("用户名: %s\n", uname)
fmt.Printf("温度: %s\n", temp)
fmt.Printf("华氏温度: %.1f°F\n", temp.Fahrenheit())
// 自定义类型需要显式转换
// var normalInt int = uid // 错误:不能直接赋值
var normalInt int = int(uid) // 正确:显式转换
fmt.Printf("转换后的整数: %d\n", normalInt)
// 类型方法的使用
fmt.Printf("摄氏温度: %.1f°C\n", temp.Celsius())
}
常量和字面量 #
1. 数值字面量 #
package main
import "fmt"
func main() {
// 整数字面量
decimal := 42 // 十进制
binary := 0b101010 // 二进制(Go 1.13+)
octal := 0o52 // 八进制(Go 1.13+)
hexadecimal := 0x2A // 十六进制
fmt.Printf("十进制: %d\n", decimal)
fmt.Printf("二进制: %d\n", binary)
fmt.Printf("八进制: %d\n", octal)
fmt.Printf("十六进制: %d\n", hexadecimal)
// 浮点数字面量
float1 := 3.14
float2 := 3.14159e2 // 科学计数法
float3 := 0x1.fp+1 // 十六进制浮点数
fmt.Printf("浮点数1: %.2f\n", float1)
fmt.Printf("浮点数2: %.2f\n", float2)
fmt.Printf("浮点数3: %.2f\n", float3)
// 数字分隔符(Go 1.13+)
million := 1_000_000
binary_with_sep := 0b1010_1010
hex_with_sep := 0xFF_FF_FF
fmt.Printf("百万: %d\n", million)
fmt.Printf("带分隔符的二进制: %d\n", binary_with_sep)
fmt.Printf("带分隔符的十六进制: %d\n", hex_with_sep)
}
2. 字符串字面量 #
package main
import "fmt"
func main() {
// 普通字符串字面量
str1 := "Hello, World!"
str2 := "包含\"引号\"的字符串"
str3 := "包含\n换行符\t制表符"
fmt.Printf("普通字符串: %s\n", str1)
fmt.Printf("包含引号: %s\n", str2)
fmt.Printf("转义字符: %s\n", str3)
// 原始字符串字面量(反引号)
rawStr := `这是原始字符串
可以包含换行符
和"引号"而不需要转义
甚至可以包含\n这样的字符`
fmt.Printf("原始字符串:\n%s\n", rawStr)
// Unicode 字符串
unicode1 := "中文字符串"
unicode2 := "\u4e2d\u6587" // Unicode 转义
unicode3 := "\U00004e2d\U00006587" // 长 Unicode 转义
fmt.Printf("中文1: %s\n", unicode1)
fmt.Printf("中文2: %s\n", unicode2)
fmt.Printf("中文3: %s\n", unicode3)
// 字符字面量
char1 := 'A'
char2 := '中'
char3 := '\n'
char4 := '\u4e2d'
fmt.Printf("字符1: %c (%d)\n", char1, char1)
fmt.Printf("字符2: %c (%d)\n", char2, char2)
fmt.Printf("字符3: %q (%d)\n", char3, char3)
fmt.Printf("字符4: %c (%d)\n", char4, char4)
}
实际应用示例 #
1. 数据验证系统 #
package main
import (
"fmt"
"strconv"
"strings"
)
// 用户年龄类型
type Age uint8
// 用户评分类型
type Rating float32
// 验证年龄
func (a Age) IsValid() bool {
return a >= 0 && a <= 150
}
// 验证评分
func (r Rating) IsValid() bool {
return r >= 0.0 && r <= 5.0
}
// 格式化评分
func (r Rating) String() string {
return fmt.Sprintf("%.1f/5.0", r)
}
// 用户信息
type UserInfo struct {
Name string
Age Age
Rating Rating
Active bool
}
func main() {
// 模拟用户输入
inputs := []map[string]string{
{"name": "张三", "age": "25", "rating": "4.5", "active": "true"},
{"name": "李四", "age": "200", "rating": "6.0", "active": "false"},
{"name": "王五", "age": "30", "rating": "3.8", "active": "yes"},
}
for i, input := range inputs {
fmt.Printf("处理用户 %d:\n", i+1)
user, err := parseUserInfo(input)
if err != nil {
fmt.Printf(" 错误: %v\n", err)
} else {
fmt.Printf(" 成功: %+v\n", user)
fmt.Printf(" 年龄有效: %t\n", user.Age.IsValid())
fmt.Printf(" 评分有效: %t\n", user.Rating.IsValid())
fmt.Printf(" 评分显示: %s\n", user.Rating)
}
fmt.Println()
}
}
func parseUserInfo(input map[string]string) (UserInfo, error) {
var user UserInfo
var err error
// 解析姓名
user.Name = strings.TrimSpace(input["name"])
if user.Name == "" {
return user, fmt.Errorf("姓名不能为空")
}
// 解析年龄
ageStr := input["age"]
ageInt, err := strconv.Atoi(ageStr)
if err != nil {
return user, fmt.Errorf("年龄格式错误: %v", err)
}
if ageInt < 0 || ageInt > 255 {
return user, fmt.Errorf("年龄超出范围: %d", ageInt)
}
user.Age = Age(ageInt)
// 解析评分
ratingStr := input["rating"]
ratingFloat, err := strconv.ParseFloat(ratingStr, 32)
if err != nil {
return user, fmt.Errorf("评分格式错误: %v", err)
}
user.Rating = Rating(ratingFloat)
// 解析活跃状态
activeStr := strings.ToLower(input["active"])
switch activeStr {
case "true", "yes", "1":
user.Active = true
case "false", "no", "0":
user.Active = false
default:
return user, fmt.Errorf("活跃状态格式错误: %s", activeStr)
}
return user, nil
}
2. 数值计算库 #
package main
import (
"fmt"
"math"
)
// 精度类型
type Precision uint8
const (
LowPrecision Precision = iota
MediumPrecision
HighPrecision
)
// 数学计算器
type Calculator struct {
precision Precision
}
// 创建计算器
func NewCalculator(p Precision) *Calculator {
return &Calculator{precision: p}
}
// 获取精度对应的小数位数
func (c *Calculator) getDecimalPlaces() int {
switch c.precision {
case LowPrecision:
return 2
case MediumPrecision:
return 6
case HighPrecision:
return 10
default:
return 2
}
}
// 格式化结果
func (c *Calculator) formatResult(result float64) string {
places := c.getDecimalPlaces()
format := fmt.Sprintf("%%.%df", places)
return fmt.Sprintf(format, result)
}
// 加法
func (c *Calculator) Add(a, b float64) string {
result := a + b
return c.formatResult(result)
}
// 除法
func (c *Calculator) Divide(a, b float64) (string, error) {
if b == 0 {
return "", fmt.Errorf("除数不能为零")
}
result := a / b
return c.formatResult(result), nil
}
// 平方根
func (c *Calculator) Sqrt(a float64) (string, error) {
if a < 0 {
return "", fmt.Errorf("负数没有实数平方根")
}
result := math.Sqrt(a)
return c.formatResult(result), nil
}
// 幂运算
func (c *Calculator) Power(base, exponent float64) string {
result := math.Pow(base, exponent)
return c.formatResult(result)
}
func main() {
// 不同精度的计算器
calculators := []*Calculator{
NewCalculator(LowPrecision),
NewCalculator(MediumPrecision),
NewCalculator(HighPrecision),
}
precisionNames := []string{"低精度", "中精度", "高精度"}
// 测试计算
a, b := 10.0, 3.0
for i, calc := range calculators {
fmt.Printf("%s计算器:\n", precisionNames[i])
// 加法
sum := calc.Add(a, b)
fmt.Printf(" %.1f + %.1f = %s\n", a, b, sum)
// 除法
if quotient, err := calc.Divide(a, b); err != nil {
fmt.Printf(" 除法错误: %v\n", err)
} else {
fmt.Printf(" %.1f ÷ %.1f = %s\n", a, b, quotient)
}
// 平方根
if sqrt, err := calc.Sqrt(a); err != nil {
fmt.Printf(" 平方根错误: %v\n", err)
} else {
fmt.Printf(" √%.1f = %s\n", a, sqrt)
}
// 幂运算
power := calc.Power(a, b)
fmt.Printf(" %.1f^%.1f = %s\n", a, b, power)
fmt.Println()
}
// 类型转换示例
fmt.Println("类型转换示例:")
// 整数运算
var x int = 10
var y int = 3
fmt.Printf("整数除法: %d ÷ %d = %d (余数: %d)\n", x, y, x/y, x%y)
// 浮点数运算
var fx float64 = float64(x)
var fy float64 = float64(y)
fmt.Printf("浮点数除法: %.1f ÷ %.1f = %.6f\n", fx, fy, fx/fy)
// 复数运算
c1 := complex(3, 4)
c2 := complex(1, 2)
fmt.Printf("复数加法: %v + %v = %v\n", c1, c2, c1+c2)
fmt.Printf("复数模长: |%v| = %.6f\n", c1, math.Sqrt(real(c1)*real(c1)+imag(c1)*imag(c1)))
}
常见错误和注意事项 #
1. 类型转换错误 #
package main
import "fmt"
func main() {
// 错误:不同数值类型不能直接运算
var a int32 = 10
var b int64 = 20
// var c = a + b // 错误:类型不匹配
// 正确:显式类型转换
var c = int64(a) + b
fmt.Printf("正确的运算: %d\n", c)
// 错误:浮点数转整数可能丢失精度
var f float64 = 3.99
var i int = int(f) // 截断,不是四舍五入
fmt.Printf("浮点数 %.2f 转整数: %d\n", f, i)
// 错误:整数溢出
var maxInt8 int8 = 127
// maxInt8++ // 溢出,变成 -128
fmt.Printf("int8 最大值: %d\n", maxInt8)
// 错误:字符串和数值不能直接转换
var str string = "123"
// var num int = int(str) // 错误
// 正确:使用 strconv 包
// num, err := strconv.Atoi(str)
// if err != nil {
// fmt.Printf("转换错误: %v\n", err)
// }
}
2. 浮点数比较问题 #
package main
import (
"fmt"
"math"
)
func main() {
// 浮点数精度问题
var a float64 = 0.1 + 0.2
var b float64 = 0.3
fmt.Printf("0.1 + 0.2 = %.17f\n", a)
fmt.Printf("0.3 = %.17f\n", b)
fmt.Printf("相等吗? %t\n", a == b)
// 正确的浮点数比较
const epsilon = 1e-9
func floatEqual(a, b float64) bool {
return math.Abs(a-b) < epsilon
}
fmt.Printf("近似相等吗? %t\n", floatEqual(a, b))
// 特殊浮点数值
var inf = math.Inf(1)
var negInf = math.Inf(-1)
var nan = math.NaN()
fmt.Printf("正无穷: %f\n", inf)
fmt.Printf("负无穷: %f\n", negInf)
fmt.Printf("NaN: %f\n", nan)
// NaN 的特殊性质
fmt.Printf("NaN == NaN: %t\n", nan == nan) // false!
fmt.Printf("IsNaN(NaN): %t\n", math.IsNaN(nan)) // true
}
小结 #
本节详细介绍了 Go 语言的基本数据类型,包括:
数值类型 #
- 整数类型:int8, int16, int32, int64, uint8, uint16, uint32, uint64, int, uint, uintptr
- 浮点数类型:float32, float64
- 复数类型:complex64, complex128
其他基本类型 #
- 布尔类型:bool
- 字符串类型:string
- 字符类型:byte (uint8), rune (int32)
重要概念 #
- 零值初始化:所有类型都有默认零值
- 类型转换:必须显式转换,注意精度丢失
- 类型别名和自定义类型:增强代码可读性和类型安全
- 字面量表示:支持多种进制和格式
最佳实践 #
- 选择合适的数据类型以节省内存
- 注意浮点数精度问题
- 使用自定义类型增强类型安全
- 正确处理类型转换和错误
理解这些基本数据类型是掌握 Go 语言的重要基础,为后续学习复合数据类型和高级特性做好准备。
练习题:
- 编写程序演示各种整数类型的取值范围
- 实现一个温度转换器,支持摄氏度、华氏度和开尔文温度
- 创建一个数值验证系统,检查输入数据的类型和范围
- 编写程序处理 Unicode 字符串,统计不同类型字符的数量
- 实现一个简单的计算器,支持不同精度的浮点数运算