一架梯子,一头程序猿,仰望星空!
Golang程序设计教程(2024版) > 内容正文

深入学习Go语言数据类型


1 Go语言数据类型简介

在Go语言中,数据类型是编程的基础,它决定了变量可以存储的数据形式。Go语言提供的基础数据类型主要有以下几类:

数据类型 描述 内存占用
bool 布尔型,用于存储真假值 1字节
int, uint 有符号和无符号整型,默认大小取决于系统平台 4或8字节
int8, uint8 8位有符号和无符号整型 1字节
int16, uint16 16位有符号和无符号整型 2字节
int32, uint32 32位有符号和无符号整型 4字节
int64, uint64 64位有符号和无符号整型 8字节
float32 32位浮点数 4字节
float64 64位浮点数 8字节
complex64 32位实数和虚数部分的复数 8字节
complex128 64位实数和虚数部分的复数 16字节
byte 类似 uint8 1字节
rune 类似 int32,表示Unicode码点 4字节
string 字符串类型 取决于字符串长度
error 错误接口,用于返回错误信息 无固定大小

这些类型可以针对不同的需求进行选择,例如数字计算、文本处理或者逻辑控制。

2 整型数据类型

2.1 整型概述

Go语言内置多种整型,分为以下几类:

  • 有符号整型:int8int16int32rune)、int64int
  • 无符号整型:uint8byte)、uint16uint32uint64uint

intuint的大小在32位系统中为4字节,在64位系统中为8字节。整型数据类型的取值范围如下表所示:

类型 取值范围
int8 -128 到 127
uint8 到 255
int16 -32768 到 32767
uint16 到 65535
int32 -2147483648 到 2147483647
uint32 到 4294967295
int64 -9223372036854775808 到 9223372036854775807
uint64 到 18446744073709551615

2.2 使用整型变量

声明整型变量的基本语法如下:

var 变量名 数据类型 = 初始值

示例代码:

package main
import "fmt"

func main() {
    var a int = 10 // 有符号整型变量
    var b uint = 20 // 无符号整型变量
    var c int8 = -128 // 最小的int8值
    fmt.Println(a, b, c)
}

2.3 整型运算

Go语言支持常见的算术运算符,例如加(+)、减(-)、乘(*)、除(/)和模(%)等,还包括位运算符如按位与(&)、或(|)、异或(^)、左移(<<)和右移(>>)。

package main
import "fmt"

func main() {
    x := 10
    y := 3

    // 算术运算
    fmt.Println(x + y) // 加法
    fmt.Println(x - y) // 减法
    fmt.Println(x * y) // 乘法
    fmt.Println(x / y) // 除法
    fmt.Println(x % y) // 取模

    // 位运算
    fmt.Println(x & y) // 按位与
    fmt.Println(x | y) // 按位或
    fmt.Println(x ^ y) // 按位异或
    fmt.Println(x << 1) // 左移1位
    fmt.Println(x >> 1) // 右移1位
}

3 浮点型数据类型

3.1 浮点型概述

Go语言中浮点型分为float32float64,分别对应32位和64位浮点数据。一般情况下,推荐使用float64因为它提供更大的范围和更准确的精度。

  • float32的有效bit位约为23个,可以提供大约7位十进制数的精度。
  • float64的有效bit位约为52个,可以提供大约16位十进制数的精度。

3.2 使用浮点型变量

声明浮点型变量可以直接给出字面量,也可以使用var关键字:

package main
import "fmt"

func main() {
    var f1 float32 = 3.14 // 显示指定 float32 类型
    f2 := 3.14            // 自动推断为 float64 类型
    fmt.Println(f1, f2)
}

3.3 浮点数的运算和问题

浮点数在运算时可能会出现精度丢失的问题。精确到很高精度的运算是一个常见问题,尤其是当两个很接近的数字做减法操作的时候。

package main
import "fmt"

func main() {
    f1 := .1
    f2 := .2
    f3 := f1 + f2
    fmt.Println(f3) // 输出可能不会是我们预期的.3,因为浮点数计算可能会有精度问题

    // 使用格式化输出修复精度问题
    fmt.Printf("%.1f\n", f3) // 输出修正为 .3
}

4 布尔型数据类型

4.1 布尔型概述

布尔型(boolean)是最简单的数据类型,仅可以取两个值:true(真)和false(假)。它在条件判断和循环控制结构中占据非常重要的位置。

4.2 使用布尔型变量

声明和使用布尔型变量:

package main
import "fmt"

func main() {
    var success bool = true
    var fail bool = false
    fmt.Println("Operation successful:", success)
    fmt.Println("Operation failed:", fail)
}

布尔值经常在条件语句中使用:

package main
import "fmt"

func main() {
    a := 10
    b := 20
    fmt.Println("a == b:", a == b) // false
    fmt.Println("a < b:", a < b)   // true
}

5 字符串数据类型

5.1 字符串概述

字符串是一系列字符的集合,在Go语言中,字符串是不可变的。每个字符串由两部分组成:一个指向底层字节数组的指针和一个长度。字符串可以包含任何数据,包括字节。

5.2 使用字符串变量

声明字符串变量通常使用双引号"来创建,也可以使用反引号`创建多行字符串:

package main
import "fmt"

func main() {
    var s1 string = "hello"
    s2 := "world"
    s3 := `This is a 
    multiple line 
    string`
    fmt.Println(s1)
    fmt.Println(s2)
    fmt.Println(s3)
}

字符串一旦创建,其内容就不可更改。下面的操作是非法的,并且会在编译时报错:

s := "hello"
s[] = 'H` // 编译错误:字符串的内容不可变

5.3 字符串操作

字符串在编程中非常常见和重要,Go语言提供了丰富的内置函数来进行字符串处理。以下是一些常用的操作。

5.3.1 字符串拼接

在Go语言中,可以使用加号(+)操作符来拼接字符串,这是最直接的方法。此外,当涉及到对多个字符串进行频繁拼接时,推荐使用strings.Builder,因为它在性能上更优。

package main

import (
    "fmt"
    "strings"
)

func main() {
    // 使用 + 拼接字符串
    hello := "Hello, "
    world := "World!"
    result := hello + world
    fmt.Println(result) // 输出: Hello, World!

    // 使用 strings.Builder 拼接字符串
    var sb strings.Builder
    sb.WriteString("Hello, ")
    sb.WriteString("World!")
    fmt.Println(sb.String()) // 输出: Hello, World!
}

5.3.2 字符串分割

字符串的分割可以使用strings.Split函数,它会根据指定的分隔符将字符串分割成一个切片(slice)。

package main

import (
    "fmt"
    "strings"
)

func main() {
    // 定义一个字符串
    sentence := "Go is an open source programming language"

    // 使用空格分割字符串
    words := strings.Split(sentence, " ")
    for _, word := range words {
        fmt.Printf("%s\n", word)
    }
    // 输出:
    // Go
    // is
    // an
    // open
    // source
    // programming
    // language
}

5.3.3 索引访问

在Go中,字符串是字节的不可变序列。可以使用索引来访问字符串中的特定字节,但需要注意的是,由于字符串可能包含多字节字符(如UTF-8编码的字符),所以直接索引可能并不会得到预期的单个字符。

package main

import "fmt"

func main() {
    s := "Hello, 世界"
    for i := ; i < len(s); i++ {
        fmt.Printf("%d: %x\n", i, s[i])
    }
    // 注意:这将输出字节的十六进制表示,而不是字符
}

如果要按字符遍历字符串,可以使用range循环。

package main

import "fmt"

func main() {
    s := "Hello, 世界"
    for index, runeValue := range s {
        fmt.Printf("%d: %U '%c'\n", index, runeValue, runeValue)
    }
    // 输出每个字符的索引、Unicode编码和字符本身
}

5.3.4 长度获取

len函数可以获得字符串的长度,即底层字节序列的长度。对于UTF-8字符串,如果需要获取字符(rune)的数量,则应使用utf8.RuneCountInString函数,这样可以正确处理多字节字符。

package main

import (
    "fmt"
    "unicode/utf8"
)

func main() {
    s := "Hello, 世界"
    fmt.Println("Bytes length:", len(s)) // 输出字节长度
    fmt.Println("Runes length:", utf8.RuneCountInString(s)) // 输出字符长度
}

通过上面的例子,我们可以看到Go语言为字符串操作提供了丰富的库函数,能够方便的完成各种字符串处理任务。在编码时要注意区分字节和字符的概念,尤其是在处理非ASCII字符集的文本时。