Go 基本数据类型
Go 是一门静态类型语言,每个变量都有确定的数据类型。理解 Go 的类型系统是编写正确、高效代码的前提。本篇将详细介绍 Go 中的整型、浮点型、布尔型、字符串、字符类型以及类型转换的方法。
整型
Go 提供了丰富的整型类型,按照位数和是否有符号进行分类。
有符号整型
| 类型 | 位数 | 取值范围 |
|---|---|---|
int8 |
8 | -128 ~ 127 |
int16 |
16 | -32768 ~ 32767 |
int32 |
32 | -2147483648 ~ 2147483647 |
int64 |
64 | -9223372036854775808 ~ 9223372036854775807 |
int |
平台相关(32位或64位) | 取决于平台 |
无符号整型
| 类型 | 位数 | 取值范围 |
|---|---|---|
uint8 |
8 | 0 ~ 255 |
uint16 |
16 | 0 ~ 65535 |
uint32 |
32 | 0 ~ 4294967295 |
uint64 |
64 | 0 ~ 18446744073709551615 |
uint |
平台相关 | 取决于平台 |
uintptr
uintptr 是一个特殊的整型,其大小足以容纳任何指针值。它主要用于底层编程和 unsafe 操作:
package main
import (
"fmt"
"unsafe"
)
func main() {
x := 42
p := &x
addr := uintptr(unsafe.Pointer(p))
fmt.Printf("变量 x 的内存地址: %d (十六进制: %x)\n", addr, addr)
}整型使用示例
package main
import (
"fmt"
"math"
)
func main() {
var a int = 100
var b int8 = 127
var c int64 = math.MaxInt64
var d uint = 200
fmt.Printf("int: %d (占 %d 字节)\n", a, unsafe.Sizeof(a))
fmt.Printf("int8: %d\n", b)
fmt.Printf("int64: %d\n", c)
fmt.Printf("uint: %d\n", d)
}注意:日常开发中,一般使用
int即可,除非有特殊的存储或协议需求。
浮点型
Go 提供两种浮点数类型:
| 类型 | 位数 | 说明 |
|---|---|---|
float32 |
32 | 单精度浮点数,约 7 位有效数字 |
float64 |
64 | 双精度浮点数,约 15 位有效数字 |
基本使用
package main
import "fmt"
func main() {
var pi32 float32 = 3.14159265358979323846
var pi64 float64 = 3.14159265358979323846
fmt.Printf("float32: %.15f\n", pi32) // 精度丢失
fmt.Printf("float64: %.15f\n", pi64) // 更精确
}精度问题
浮点数运算存在精度问题,这在所有编程语言中都是如此:
package main
import "fmt"
func main() {
a := 0.1
b := 0.2
c := a + b
fmt.Println(c) // 0.30000000000000004
fmt.Println(c == 0.3) // false
// 正确做法:使用误差范围比较
const epsilon = 1e-9
if c-0.3 < epsilon && c-0.3 > -epsilon {
fmt.Println("a + b 约等于 0.3")
}
}建议:涉及金额计算时,使用整数(以分为单位)或
math/big包来避免精度问题。
布尔型
Go 的布尔类型只有两个值:true 和 false。
package main
import "fmt"
func main() {
var isActive bool // 零值为 false
isReady := true
fmt.Println("isActive:", isActive) // false
fmt.Println("isReady:", isReady) // true
// 布尔值不能与整数互相转换
// var n int = 1
// isActive = bool(n) // 编译错误!
_ = isReady
}注意:Go 中布尔值不能像 C 语言那样用 0/1 替代,也不能隐式转换为整数。
字符串
字符串是 Go 中最常用的数据类型之一。Go 中的字符串是不可变的字节序列。
基本操作
package main
import "fmt"
func main() {
// 双引号声明(支持转义字符)
s1 := "Hello, Go!"
// 反引号声明(原始字符串,不支持转义,支持换行)
s2 := `这是一个
多行字符串
不需要转义 \n`
fmt.Println(s1)
fmt.Println(s2)
// 字符串长度
fmt.Println("长度:", len(s1)) // 11
// 字符串拼接
greeting := "Hello" + ", " + "World!"
fmt.Println(greeting)
}字节 vs Rune
字符串底层是字节(byte)序列。访问字符串中的单个字符时需要注意中文等多字节字符:
package main
import "fmt"
func main() {
s := "Hello世界"
// 按字节访问 —— 中文会被拆成多个字节
fmt.Println("按字节遍历:")
for i := 0; i < len(s); i++ {
fmt.Printf("%c (%d) ", s[i], s[i])
}
fmt.Println()
// 按 rune 访问 —— 正确处理 Unicode 字符
fmt.Println("按 rune 遍历:")
for _, r := range s {
fmt.Printf("%c (%d) ", r, r)
}
fmt.Println()
// 字节长度 vs 字符数
fmt.Println("字节长度:", len(s)) // 13
fmt.Println("字符数量:", len([]rune(s))) // 7
}常用字符串操作
package main
import (
"fmt"
"strings"
)
func main() {
s := " Hello, Go World! "
// 去除首尾空白
trimmed := strings.TrimSpace(s)
fmt.Println(trimmed) // "Hello, Go World!"
// 查找子串
fmt.Println(strings.Contains(trimmed, "Go")) // true
fmt.Println(strings.Index(trimmed, "World")) // 10
// 替换
replaced := strings.Replace(trimmed, "Go", "Golang", 1)
fmt.Println(replaced) // "Hello, Golang World!"
// 分割
parts := strings.Split("a,b,c,d", ",")
fmt.Println(parts) // [a b c d]
// 拼接
joined := strings.Join(parts, "-")
fmt.Println(joined) // "a-b-c-d"
// 大小写转换
fmt.Println(strings.ToUpper("hello")) // HELLO
fmt.Println(strings.ToLower("WORLD")) // world
// 格式化字符串
name := "张三"
age := 25
info := fmt.Sprintf("姓名: %s, 年龄: %d", name, age)
fmt.Println(info)
}字符类型
Go 中没有专门的字符类型,而是用以下两种方式表示字符:
byte(等同于 uint8)
byte 表示 ASCII 字符或 UTF-8 编码中的一个字节:
package main
import "fmt"
func main() {
var b byte = 'A'
fmt.Printf("字符: %c, ASCII 码: %d\n", b, b)
fmt.Printf("byte 的底层类型是 uint8: %T\n", b)
}rune(等同于 int32)
rune 表示一个 Unicode 码点,可以表示任何语言的字符:
package main
import "fmt"
func main() {
var r rune = '中'
fmt.Printf("字符: %c, Unicode: %U\n", r, r)
fmt.Printf("rune 的底层类型是 int32: %T\n", r)
// 各种语言的字符
chars := []rune{'你', '好', '世', '界', '🌍'}
for _, c := range chars {
fmt.Printf("%c ", c)
}
fmt.Println()
}byte 与 rune 的选择
- 处理 ASCII 文本或二进制数据时,使用
byte。 - 处理包含中文等非 ASCII 字符的文本时,使用
rune。
类型转换
Go 是强类型语言,不支持隐式类型转换,必须显式转换。
基本类型转换
package main
import "fmt"
func main() {
// 整型之间的转换
var a int = 100
var b int64 = int64(a)
var c float64 = float64(a)
var d int = int(3.99) // 截断小数部分,结果为 3
fmt.Printf("int -> int64: %d (%T)\n", b, b)
fmt.Printf("int -> float64: %f (%T)\n", c, c)
fmt.Printf("float64 -> int: %d (%T)\n", d, d)
}使用 strconv 包进行字符串转换
package main
import (
"fmt"
"strconv"
)
func main() {
// 整数转字符串
s1 := strconv.Itoa(42) // int to ascii
fmt.Printf("Itoa: %q\n", s1) // "42"
// 字符串转整数
n, err := strconv.Atoi("123")
if err != nil {
fmt.Println("转换错误:", err)
}
fmt.Printf("Atoi: %d\n", n)
// 其他进制转换
s2 := strconv.FormatInt(255, 16) // 十进制转十六进制
fmt.Println("255 的十六进制:", s2) // "ff"
n2, _ := strconv.ParseInt("ff", 16, 64) // 十六进制转十进制
fmt.Println("0xff 的十进制:", n2) // 255
// 浮点数与字符串互转
s3 := strconv.FormatFloat(3.14, 'f', 2, 64)
fmt.Println("浮点数转字符串:", s3) // "3.14"
f, _ := strconv.ParseFloat("2.718", 64)
fmt.Println("字符串转浮点数:", f) // 2.718
// 布尔值与字符串互转
s4 := strconv.FormatBool(true)
fmt.Println("布尔转字符串:", s4) // "true"
b, _ := strconv.ParseBool("false")
fmt.Println("字符串转布尔:", b) // false
}零值总结表
| 类型 | 零值 | 示例 |
|---|---|---|
int, int8, int16, int32, int64 |
0 |
var n int → 0 |
uint, uint8, uint16, uint32, uint64 |
0 |
var u uint → 0 |
uintptr |
0 |
var p uintptr → 0 |
float32, float64 |
0.0 |
var f float64 → 0 |
bool |
false |
var b bool → false |
string |
"" |
var s string → "" |
byte (uint8) |
0 |
var b byte → 0 |
rune (int32) |
0 |
var r rune → 0 |
| 指针、函数、接口、slice、channel、map | nil |
var p *int → nil |
总结
本篇详细介绍了 Go 的基本数据类型:整型(int 系列和 uint 系列)、浮点型(float32/float64)、布尔型(bool)、字符串(string)以及字符表示方式(byte 和 rune)。我们了解了浮点数精度问题的本质及应对方法,掌握了字符串的字节与 rune 遍历方式,以及使用 strconv 包进行类型转换的技巧。Go 的强类型系统要求显式类型转换,虽然多写了几行代码,但大大减少了运行时的类型错误。